From 91dfea313808f279b243b1abe5a1668415c6d048 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Sun, 7 Dec 2025 20:15:41 +0100 Subject: [PATCH 01/11] feat: Add remote-servers configuration for BIND 9.20 - Create new remote-servers template - Integrate into configuration generator --- templates/named.conf.generator.j2 | 3 +++ templates/named.conf.remote-servers.j2 | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+) create mode 100644 templates/named.conf.remote-servers.j2 diff --git a/templates/named.conf.generator.j2 b/templates/named.conf.generator.j2 index ba4e518..0199e32 100644 --- a/templates/named.conf.generator.j2 +++ b/templates/named.conf.generator.j2 @@ -54,3 +54,6 @@ {% if item.view is defined and item.view %} {% include 'named.conf.view.j2' %} {% endif %} +{% if item.remote_servers is defined and item.remote_servers %} +{% include 'named.conf.remote-servers.j2' %} +{% endif %} diff --git a/templates/named.conf.remote-servers.j2 b/templates/named.conf.remote-servers.j2 new file mode 100644 index 0000000..08b1fe3 --- /dev/null +++ b/templates/named.conf.remote-servers.j2 @@ -0,0 +1,20 @@ +{% for server in item.remote_servers %} +remote-servers "{{ server.name }}" { +{% filter indent(bind9_config_indent, true) %} +{% for key, value in server.items() %} +{% if key != 'name' %} +{# Handle known complex types if any, otherwise default to simple string/block #} +{% if value is iterable and value is not string and value is not mapping %} +{{ key }} { + {% for subitem in value %} + {{ subitem }}; + {% endfor %} +}; +{% else %} +{{ key }} {{ value }}; +{% endif %} +{% endif %} +{% endfor %} +{% endfilter %} +}; +{% endfor %} From 7903afdcd3589fac77cd762ac1b856e893f0c5e9 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Sun, 7 Dec 2025 20:15:54 +0100 Subject: [PATCH 02/11] refactor: Implement dynamic ordering in BIND templates - Simplify options and zone templates - Add deprecation warnings for legacy configurations - Reduce template complexity and improve maintainability --- templates/named.conf.options.j2 | 533 +++++++++----------------------- templates/named.conf.zone.j2 | 199 ++++-------- 2 files changed, 215 insertions(+), 517 deletions(-) diff --git a/templates/named.conf.options.j2 b/templates/named.conf.options.j2 index afdbaf7..d5fd43d 100644 --- a/templates/named.conf.options.j2 +++ b/templates/named.conf.options.j2 @@ -1,22 +1,28 @@ +{% import 'named.conf.functions.j2' as functions with context %} options { {% filter indent(bind9_config_indent,true)%} -{# Unicorn Options#} -{% if item.options.rrset_order is defined and item.options.rrset_order %} +{# Iterate over keys to preserve user order (Python 3.7+ / Ansible dicts are ordered) #} +{% for key, value in item.options.items() %} +{% set conf_key = key | replace('_', '-') %} + +{# --- COMPLEX BLOCKS --- #} + +{% if key == 'rrset_order' %} rrset-order { {% filter indent(bind9_config_indent, true) %} -{% for rrset in item.options.rrset_order %} +{% for rrset in value %} {{ ('class ' + rrset.class | string + ' ') if rrset.class is defined and rrset.class -}} {{ ('type ' + rrset.type | string + ' ') if rrset.type is defined and rrset.type -}} {{ ('name "' + rrset.name | string + '" ') if rrset.name is defined and rrset.name -}} {{ ('order ' + rrset.order | string) -}}; {% endfor %} {% endfilter %}}; -{% endif %} -{% if item.options.response_policy is defined and item.options.response_policy %} + +{% elif key == 'response_policy' %} response-policy { {% filter indent(bind9_config_indent, true) %} -{% for zone in item.options.response_policy.zones %} +{% for zone in value.zones %} {{- ('zone ' + zone.zone | string) -}} {{- (' max-policy-ttl ' + zone.max_policy_ttl | string) if zone.max_policy_ttl is defined and zone.max_policy_ttl -}} {{- (' min-update-interval ' + zone.min_update_interval | string) if zone.min_update_interval is defined and zone.min_update_interval -}} @@ -28,108 +34,86 @@ response-policy { {{- (' nsdname-enable ' + functions.named_boolean(zone.nsdname_enable)) if zone.nsdname_enable is defined }}; {% endfor %} {% endfilter %}} -{{- (' max-policy-ttl ' + item.options.response_policy.max_policy_ttl | string) if item.options.response_policy.max_policy_ttl is defined and item.options.response_policy.max_policy_ttl -}} -{{- (' min-update-interval ' + item.options.response_policy.min_update_interval | string) if item.options.response_policy.min_update_interval is defined and item.options.response_policy.min_update_interval -}} -{{- (' min-ns-dots ' + item.options.response_policy.min_ns_dots | string) if item.options.response_policy.min_ns_dots is defined and item.options.response_policy.min_ns_dots -}} -{{- (' add-soa ' + functions.named_boolean(item.options.response_policy.add_soa)) if item.options.response_policy.add_soa is defined -}} -{{- (' break-dnssec ' + functions.named_boolean(item.options.response_policy.break_dnssec)) if item.options.response_policy.break_dnssec is defined -}} -{{- (' nsip-wait-recurse ' + functions.named_boolean(item.options.response_policy.nsip_wait_recurse)) if item.options.response_policy.nsip_wait_recurse is defined -}} -{{- (' nsdname-wait-recurse ' + functions.named_boolean(item.options.response_policy.nsdname_wait_recurse)) if item.options.response_policy.nsdname_wait_recurse is defined -}} -{{- (' qname-wait-recurse ' + functions.named_boolean(item.options.response_policy.qname_wait_recurse)) if item.options.response_policy.qname_wait_recurse is defined -}} -{{- (' recursive-only ' + functions.named_boolean(item.options.response_policy.recursive_only)) if item.options.response_policy.recursive_only is defined -}} -{{- (' nsip-enable ' + functions.named_boolean(item.options.response_policy.nsip_enable)) if item.options.response_policy.nsip_enable is defined -}} -{{- (' nsdname-enable ' + functions.named_boolean(item.options.response_policy.nsdname_enable)) if item.options.response_policy.nsdname_enable is defined -}} -{{- (' dnsrps-enable ' + functions.named_boolean(item.options.response_policy.dnsrps_enable)) if item.options.response_policy.dnsrps_enable is defined -}} -{{- (' dnsrps-options { ' + item.options.response_policy.dnsrps_options | join('; ') + '; }') if item.options.response_policy.dnsrps_options is defined and item.options.response_policy.dnsrps_options -}}; -{% endif %} -{% if item.options.response_padding is defined and item.options.response_padding %} +{{- (' max-policy-ttl ' + value.max_policy_ttl | string) if value.max_policy_ttl is defined and value.max_policy_ttl -}} +{{- (' min-update-interval ' + value.min_update_interval | string) if value.min_update_interval is defined and value.min_update_interval -}} +{{- (' min-ns-dots ' + value.min_ns_dots | string) if value.min_ns_dots is defined and value.min_ns_dots -}} +{{- (' add-soa ' + functions.named_boolean(value.add_soa)) if value.add_soa is defined -}} +{{- (' break-dnssec ' + functions.named_boolean(value.break_dnssec)) if value.break_dnssec is defined -}} +{{- (' nsip-wait-recurse ' + functions.named_boolean(value.nsip_wait_recurse)) if value.nsip_wait_recurse is defined -}} +{{- (' nsdname-wait-recurse ' + functions.named_boolean(value.nsdname_wait_recurse)) if value.nsdname_wait_recurse is defined -}} +{{- (' qname-wait-recurse ' + functions.named_boolean(value.qname_wait_recurse)) if value.qname_wait_recurse is defined -}} +{{- (' recursive-only ' + functions.named_boolean(value.recursive_only)) if value.recursive_only is defined -}} +{{- (' nsip-enable ' + functions.named_boolean(value.nsip_enable)) if value.nsip_enable is defined -}} +{{- (' nsdname-enable ' + functions.named_boolean(value.nsdname_enable)) if value.nsdname_enable is defined -}} +{{- (' dnsrps-enable ' + functions.named_boolean(value.dnsrps_enable)) if value.dnsrps_enable is defined -}} +{{- (' dnsrps-options { ' + value.dnsrps_options | join('; ') + '; }') if value.dnsrps_options is defined and value.dnsrps_options -}}; + +{% elif key == 'response_padding' %} response-padding { -{{ functions.simple_item_list(item.options.response_padding.addresses) }}} -{{- (' block-size ' + item.options.response_padding.block_size | string) }}; -{% endif %} -{% if item.options.rate_limit is defined and item.options.rate_limit %} +{{ functions.simple_item_list(value.addresses) }}} +{{- (' block-size ' + value.block_size | string) }}; + +{% elif key == 'rate_limit' %} rate-limit { {% filter indent(bind9_config_indent, true) %} -{{ ('all-per-second ' + item.options.rate_limit.all_per_second | string + ';\n') if item.options.rate_limit.all_per_second is defined and item.options.rate_limit.all_per_second -}} -{{ ('errors-per-second ' + item.options.rate_limit.errors_per_second | string + ';\n') if item.options.rate_limit.errors_per_second is defined and item.options.rate_limit.errors_per_second -}} -{{ ('responses-per-second ' + item.options.rate_limit.responses_per_second | string + ';\n') if item.options.rate_limit.responses_per_second is defined and item.options.rate_limit.responses_per_second -}} -{{ ('referrals-per-second ' + item.options.rate_limit.referrals_per_second | string + ';\n') if item.options.rate_limit.referrals_per_second is defined and item.options.rate_limit.referrals_per_second -}} -{{ ('nodata-per-second ' + item.options.rate_limit.nodata_per_second | string + ';\n') if item.options.rate_limit.nodata_per_second is defined and item.options.rate_limit.nodata_per_second -}} -{{ ('nxdomains-per-second ' + item.options.rate_limit.nxdomains_per_second | string + ';\n') if item.options.rate_limit.nxdomains_per_second is defined and item.options.rate_limit.nxdomains_per_second -}} -{{ ('ipv4-prefix-length ' + item.options.rate_limit.ipv4_prefix_length | string + ';\n') if item.options.rate_limit.ipv4_prefix_length is defined and item.options.rate_limit.ipv4_prefix_length -}} -{{ ('ipv6-prefix-length ' + item.options.rate_limit.ipv6_prefix_length | string + ';\n') if item.options.rate_limit.ipv6_prefix_length is defined and item.options.rate_limit.ipv6_prefix_length -}} -{{ ('max-table-size ' + item.options.rate_limit.max_table_size | string + ';\n') if item.options.rate_limit.max_table_size is defined and item.options.rate_limit.max_table_size -}} -{{ ('min-table-size ' + item.options.rate_limit.min_table_size | string + ';\n') if item.options.rate_limit.min_table_size is defined and item.options.rate_limit.min_table_size -}} -{{ ('qps-scale ' + item.options.rate_limit.qps_scale | string + ';\n') if item.options.rate_limit.qps_scale is defined and item.options.rate_limit.qps_scale -}} -{{ ('window ' + item.options.rate_limit.window | string + ';\n') if item.options.rate_limit.window is defined and item.options.rate_limit.window -}} -{{ ('slip ' + item.options.rate_limit.slip | string + ';\n') if item.options.rate_limit.slip is defined and item.options.rate_limit.slip -}} -{{ ('log-only ' + functions.named_boolean(item.options.rate_limit.log_only) + ';\n') if item.options.rate_limit.log_only is defined -}} -{{ ('exempt-clients {\n' + functions.simple_item_list(item.options.rate_limit.exempt_clients) + '};\n') if item.options.rate_limit.exempt_clients is defined and item.options.rate_limit.exempt_clients -}} +{{ ('all-per-second ' + value.all_per_second | string + ';\n') if value.all_per_second is defined and value.all_per_second -}} +{{ ('errors-per-second ' + value.errors_per_second | string + ';\n') if value.errors_per_second is defined and value.errors_per_second -}} +{{ ('responses-per-second ' + value.responses_per_second | string + ';\n') if value.responses_per_second is defined and value.responses_per_second -}} +{{ ('referrals-per-second ' + value.referrals_per_second | string + ';\n') if value.referrals_per_second is defined and value.referrals_per_second -}} +{{ ('nodata-per-second ' + value.nodata_per_second | string + ';\n') if value.nodata_per_second is defined and value.nodata_per_second -}} +{{ ('nxdomains-per-second ' + value.nxdomains_per_second | string + ';\n') if value.nxdomains_per_second is defined and value.nxdomains_per_second -}} +{{ ('ipv4-prefix-length ' + value.ipv4_prefix_length | string + ';\n') if value.ipv4_prefix_length is defined and value.ipv4_prefix_length -}} +{{ ('ipv6-prefix-length ' + value.ipv6_prefix_length | string + ';\n') if value.ipv6_prefix_length is defined and value.ipv6_prefix_length -}} +{{ ('max-table-size ' + value.max_table_size | string + ';\n') if value.max_table_size is defined and value.max_table_size -}} +{{ ('min-table-size ' + value.min_table_size | string + ';\n') if value.min_table_size is defined and value.min_table_size -}} +{{ ('qps-scale ' + value.qps_scale | string + ';\n') if value.qps_scale is defined and value.qps_scale -}} +{{ ('window ' + value.window | string + ';\n') if value.window is defined and value.window -}} +{{ ('slip ' + value.slip | string + ';\n') if value.slip is defined and value.slip -}} +{{ ('log-only ' + functions.named_boolean(value.log_only) + ';\n') if value.log_only is defined -}} +{{ ('exempt-clients {\n' + functions.simple_item_list(value.exempt_clients) + '};\n') if value.exempt_clients is defined and value.exempt_clients -}} {% endfilter %}}; -{% endif %} -{% if item.options.listen_on_v6 is defined and item.options.listen_on_v6 %} -{% for listen in item.options.listen_on_v6 if item.options.listen_on_v6 is not mapping %} -listen-on-v6 + +{% elif key == 'listen_on_v6' or key == 'listen_on' %} +{% for listen in (value if value is not mapping else [value]) %} +{{ conf_key }} {{- (' port ' + listen.port | string) if listen.port is defined and listen.port -}} {{- (' dscp ' + listen.dscp | string) if listen.dscp is defined and listen.dscp -}} {{- (' tls ' + listen.tls | string) if listen.tls is defined and listen.tls -}} {{- (' http ' + listen.http | string) if listen.http is defined and listen.http }} { {{ functions.simple_item_list(listen.addresses) }}}; -{% else %} -listen-on-v6 -{{- (' port ' + item.options.listen_on_v6.port | string) if item.options.listen_on_v6.port is defined and item.options.listen_on_v6.port -}} -{{- (' dscp ' + item.options.listen_on_v6.dscp | string) if item.options.listen_on_v6.dscp is defined and item.options.listen_on_v6.dscp -}} -{{- (' tls ' + item.options.listen_on_v6.tls | string) if item.options.listen_on_v6.tls is defined and item.options.listen_on_v6.tls -}} -{{- (' http ' + item.options.listen_on_v6.http | string) if item.options.listen_on_v6.http is defined and item.options.listen_on_v6.http }} { -{{ functions.simple_item_list(item.options.listen_on_v6.addresses) }}}; {% endfor %} -{% endif %} -{% if item.options.listen_on is defined and item.options.listen_on %} -{% for listen in item.options.listen_on if item.options.listen_on is not mapping %} -listen-on -{{- (' port ' + listen.port | string) if listen.port is defined and listen.port -}} -{{- (' dscp ' + listen.dscp | string) if listen.dscp is defined and listen.dscp -}} -{{- (' tls ' + listen.tls | string) if listen.tls is defined and listen.tls -}} -{{- (' http ' + listen.http | string) if listen.http is defined and listen.http }} { -{{ functions.simple_item_list(listen.addresses) }}}; -{% else %} -listen-on -{{- (' port ' + item.options.listen_on.port | string) if item.options.listen_on.port is defined and item.options.listen_on.port -}} -{{- (' dscp ' + item.options.listen_on.dscp | string) if item.options.listen_on.dscp is defined and item.options.listen_on.dscp -}} -{{- (' tls ' + item.options.listen_on.tls | string) if item.options.listen_on.tls is defined and item.options.listen_on.tls -}} -{{- (' http ' + item.options.listen_on.http | string) if item.options.listen_on.http is defined and item.options.listen_on.http }} { -{{ functions.simple_item_list(item.options.listen_on.addresses) }}}; -{% endfor %} -{% endif %} -{{ functions.parent_address_port_dscp("forwarders", item.options.forwarders) if item.options.forwarders is defined and item.options.forwarders -}} -{% if item.options.dual_stack_servers is defined and item.options.dual_stack_servers %} + +{% elif key == 'forwarders' %} +{{ functions.parent_address_port_dscp("forwarders", value) -}} + +{% elif key == 'dual_stack_servers' %} dual-stack-servers -{{ (' port ' + item.options.dual_stack_servers.port | string) if item.options.dual_stack_servers.port is defined and item.options.dual_stack_servers }} { -{% for host in item.options.dual_stack_servers.addresses %} +{{ (' port ' + value.port | string) if value.port is defined and value }} { +{% for host in value.addresses %} {% filter indent(bind9_config_indent, true) %} {{ host.address | ansible.utils.ipaddr | ternary(host.address, '"' + host.address + '"') }} {{- (' port ' + host.port | string) if host.port is defined and host.port -}} {{- (' dscp ' + host.dscp | string) if host.dscp is defined and host.dscp -}}; {% endfilter %} {% endfor %}}; -{% endif %} -{% if item.options.dnstap_output is defined and item.options.dnstap_output %} -dnstap-output {{ item.options.dnstap_output.output_type -}} -{{- ' "' + item.options.dnstap_output.output_file + '"' -}} -{{- (' size ' + item.options.dnstap_output.size | string) if item.options.dnstap_output.size is defined and item.options.dnstap_output.size -}} -{{- (' versions ' + item.options.dnstap_output.versions | string) if item.options.dnstap_output.versions is defined and item.options.dnstap_output.versions -}} -{{- (' suffix ' + item.options.dnstap_output.suffix | string) if item.options.dnstap_output.suffix is defined and item.options.dnstap_output.suffix -}}; -{% endif %} -{% if item.options.dnstap is defined and item.options.dnstap %} + +{% elif key == 'dnstap_output' %} +dnstap-output {{ value.output_type -}} +{{- ' "' + value.output_file + '"' -}} +{{- (' size ' + value.size | string) if value.size is defined and value.size -}} +{{- (' versions ' + value.versions | string) if value.versions is defined and value.versions -}} +{{- (' suffix ' + value.suffix | string) if value.suffix is defined and value.suffix -}}; + +{% elif key == 'dnstap' %} dnstap { {% filter indent(bind9_config_indent, true) %} -{% for dnstap in item.options.dnstap %} +{% for dnstap in value %} {{ dnstap.type }}{{ ' ' + dnstap.log if dnstap.log is defined and dnstap.log }}; {% endfor %} {% endfilter %}}; -{% endif %} -{% if item.options.dns64 is defined and item.options.dns64 %} -{% for dns64 in item.options.dns64 if item.options.dns64 is sequence %} + +{% elif key == 'dns64' %} +{% for dns64 in (value if value is sequence else [value]) %} dns64 {{ dns64.netprefix }} { {% filter indent(bind9_config_indent, true) %} {{ ('break-dnssec ' + functions.named_boolean(dns64.break_dnssec) + ';\n') if dns64.break_dnssec is defined and dns64.break_dnssec is boolean -}} @@ -140,31 +124,31 @@ dns64 {{ dns64.netprefix }} { {{ ("mapped {\n" + functions.simple_item_list(dns64.mapped) + "};\n") if dns64.mapped is defined and dns64.mapped -}} {% endfilter %}}; {% endfor %} -{% endif %} -{% if item.options.deny_answer_aliases is defined and item.options.deny_answer_aliases %} + +{% elif key == 'deny_answer_aliases' %} deny-answer-aliases { -{{ functions.simple_item_list(item.options.deny_answer_aliases.names) }}} -{%- if item.options.deny_answer_aliases.except_from is defined and item.options.deny_answer_aliases.except_from %} +{{ functions.simple_item_list(value.names) }}} +{%- if value.except_from is defined and value.except_from %} except-from { -{{ functions.simple_item_list(item.options.deny_answer_aliases.except_from, 4) }}} +{{ functions.simple_item_list(value.except_from, 4) }}} {%- endif %}; -{% endif %} -{% if item.options.deny_answer_addresses is defined and item.options.deny_answer_addresses %} + +{% elif key == 'deny_answer_addresses' %} deny-answer-addresses { -{{ functions.simple_item_list(item.options.deny_answer_addresses.addresses) }}} -{%- if item.options.deny_answer_addresses.except_from is defined and item.options.deny_answer_addresses.except_from %} +{{ functions.simple_item_list(value.addresses) }}} +{%- if value.except_from is defined and value.except_from %} except-from { -{{ functions.simple_item_list(item.options.deny_answer_addresses.except_from, 4) }}} +{{ functions.simple_item_list(value.except_from, 4) }}} {%- endif %}; -{% endif %} -{% if item.options.check_names is defined and item.options.check_names %} -{% for policy in item.options.check_names %} + +{% elif key == 'check_names' %} +{% for policy in value %} check-names {{ policy.type }} {{ policy.action }}; {% endfor %} -{% endif %} -{% if item.options.catalog_zones is defined and item.options.catalog_zones %} + +{% elif key == 'catalog_zones' %} catalog-zones { -{% for catalog_zone in item.options.catalog_zones %} +{% for catalog_zone in value %} zone {{ catalog_zone.zone }} {% filter indent(bind9_config_indent, true) %} {% if catalog_zone.default_primaries is defined and catalog_zone.default_primaries %} @@ -178,291 +162,80 @@ default-primaries {{ ('min-update-interval ' + catalog_zone.min_update_interval | string) if catalog_zone.min_update_interval is defined and catalog_zone.min_update_interval}}; {% endfilter %} {% endfor %}}; -{% endif %} -{{ functions.single_ip_port_dscp('transfer-source', item.options.transfer_source) if item.options.transfer_source is defined and item.options.transfer_source -}} -{{ functions.single_ip_port_dscp('transfer-source-v6', item.options.transfer_source_v6) if item.options.transfer_source_v6 is defined and item.options.transfer_source_v6 -}} -{{ functions.single_ip_port_dscp('alt-transfer-source', item.options.alt_transfer_source) if item.options.alt_transfer_source is defined and item.options.alt_transfer_source -}} -{{ functions.single_ip_port_dscp('alt-transfer-source-v6', item.options.alt_transfer_source_v6) if item.options.alt_transfer_source_v6 is defined and item.options.alt_transfer_source_v6 -}} -{{ functions.single_ip_port_dscp('query-source', item.options.query_source) if item.options.query_source is defined and item.options.query_source -}} -{{ functions.single_ip_port_dscp('query-source-v6', item.options.query_source_v6) if item.options.query_source_v6 is defined and item.options.query_source_v6 -}} -{{ functions.single_ip_port_dscp('parental-source', item.options.parental_source) if item.options.parental_source is defined and item.options.parental_source -}} -{{ functions.single_ip_port_dscp('parental-source-v6', item.options.parental_source_v6) if item.options.parental_source_v6 is defined and item.options.parental_source_v6 -}} -{{ functions.single_ip_port_dscp('notify-source', item.options.notify_source) if item.options.notify_source is defined and item.options.notify_source -}} -{{ functions.single_ip_port_dscp('notify-source-v6', item.options.notify_source_v6) if item.options.notify_source_v6 is defined and item.options.notify_source_v6 -}} -{% if item.options.also_notify is defined and item.options.also_notify is not string %} + +{% elif key in ['transfer_source', 'transfer_source_v6', 'alt_transfer_source', 'alt_transfer_source_v6', 'query_source', 'query_source_v6', 'parental_source', 'parental_source_v6', 'notify_source', 'notify_source_v6'] %} +{{ functions.single_ip_port_dscp(conf_key, value) -}} + +{% elif key == 'also_notify' and value is not string %} also-notify -{{- (' port ' + item.options.also_notify.port | string) if item.options.also_notify.port is defined and item.options.also_notify.port -}} -{{- (' dscp ' + item.options.also_notify.dscp | string) if item.options.also_notify.dscp is defined and item.options.also_notify.dscp }} { -{{ functions.list_address_port_key_tls(item.options.also_notify.addresses) }}}; -{% endif %} -{% if item.options.allow_transfer is defined and item.options.allow_transfer is not string %} +{{- (' port ' + value.port | string) if value.port is defined and value.port -}} +{{- (' dscp ' + value.dscp | string) if value.dscp is defined and value.dscp }} { +{{ functions.list_address_port_key_tls(value.addresses) }}}; + +{% elif key == 'allow_transfer' and value is not string %} allow-transfer -{{- (' port ' + item.options.allow_transfer.port | string) if item.options.allow_transfer.port is defined and item.options.allow_transfer.port -}} -{{- (' transport ' + item.options.allow_transfer.transport) if item.options.allow_transfer.transport is defined and item.options.allow_transfer.transport }} { -{{ functions.simple_item_list(item.options.allow_transfer.addresses) }}}; -{% endif %} -{# The rest #} -{% if item.options.disable_algorithms is defined and item.options.disable_algorithms %} -{% for item in item.options.disable_algorithms %} +{{- (' port ' + value.port | string) if value.port is defined and value.port -}} +{{- (' transport ' + value.transport) if value.transport is defined and value.transport }} { +{{ functions.simple_item_list(value.addresses) }}}; + +{% elif key == 'disable_algorithms' %} +{% for item in value %} disable-algorithms {{ item.domain }} { "{{ item.algorithms | join('"; "') }}"; }; {% endfor %} -{% endif %} -{% if item.options.disable_ds_digests is defined and item.options.disable_ds_digests %} -{% for item in item.options.disable_ds_digests %} + +{% elif key == 'disable_ds_digests' %} +{% for item in value %} disable-ds-digests {{ item.domain }} { "{{ item.digests | join('"; "') }}"; }; {% endfor %} -{% endif %} -{# Oddball simple options #} -{% if item.options.fetch_quota_params is defined and item.options.fetch_quota_params is string %} -fetch-quota-params {{ item.options.fetch_quota_params }}; -{% endif %} -{% if item.options.fetches_per_server is defined and item.options.fetches_per_server is string %} -fetches-per-server {{ item.options.fetches_per_server }}; -{% endif %} -{% if item.options.fetches_per_zone is defined and item.options.fetches_per_zone is string %} -fetches-per-zone {{ item.options.fetches_per_zone }}; -{% endif %} -{% if item.options.prefetch is defined and item.options.prefetch %} -prefetch {{ item.options.prefetch }}; -{% endif %} -{% if item.options.root_delegation_only is defined and item.options.root_delegation_only %} -root-delegation-only{% if item.options.root_delegation_only.exclude is defined and item.options.root_delegation_only.exclude is sequence %} exclude { -{{ functions.simple_item_list(item.options.root_delegation_only.exclude) }}} + +{% elif key == 'root_delegation_only' %} +root-delegation-only{% if value.exclude is defined and value.exclude is sequence %} exclude { +{{ functions.simple_item_list(value.exclude) }}} {% endif %}; + +{% elif key == 'tkey_dhkey' %} +tkey-dhkey "{{ value.key_name }}" {{ value.key_tag }}; + +{# --- SPECIAL QUOTED STRINGS --- #} +{% elif key in ['dnstap_identity', 'server_id'] %} +{{ functions.reserved_or_quoted(conf_key, value, ['none', 'hostname']) -}} + +{% elif key in ['dnstap_version', 'geoip_directory', 'hostname', 'lock_file', 'pid_file', 'random_device', 'session_keyfile', 'version'] %} +{{ functions.reserved_or_quoted(conf_key, value, ['none']) -}} + +{# --- DEPRECATED/OBSOLETE --- #} +{% elif key == 'tkey_domain' %} +{# Obsolete in 9.20 #} +/* WARN: tkey-domain is obsolete in BIND 9.20 */ +{{ functions.reserved_or_quoted(conf_key, value, ['none']) -}} + +{% elif key == 'tkey_gssapi_credential' %} +{# Deprecated in 9.20 #} +/* WARN: tkey-gssapi-credential is deprecated in BIND 9.20; use tkey-gssapi-keytab */ +{{ functions.reserved_or_quoted(conf_key, value, ['none']) -}} + +{# --- SIMPLE LISTS --- #} +{% elif key in ['allow_notify', 'allow_query', 'allow_query_cache', 'allow_query_cache_on', 'allow_query_on', 'allow_recursion', 'allow_recursion_on', 'allow_update', 'allow_update_forwarding', 'blackhole', 'keep_response_order', 'no_case_compress', 'sortlist', 'avoid_v4_udp_ports', 'avoid_v6_udp_ports', 'use_v4_udp_ports', 'use_v6_udp_ports', 'validate_except'] %} +{{ conf_key }} { +{{ functions.simple_item_list(value) }}}; + +{# --- QUOTED STRINGS --- #} +{% elif key in ['bindkeys_file', 'directory', 'dump_file', 'key_directory', 'managed_keys_directory', 'memstatistics_file', 'new_zones_directory', 'recursing_file', 'secroots_file', 'statistics_file', 'tkey_gssapi_keytab'] %} +{{ conf_key }} "{{ value }}"; + +{# --- BOOLEANS --- #} +{% elif key in ['allow_new_zones', 'answer_cookie', 'auth_nxdomain', 'automatic_interface_scan', 'check_integrity', 'check_sibling', 'check_wildcard', 'dnsrps_enable', 'dnssec_accept_expired', 'dnssec_dnskey_kskonly', 'dnssec_secure_to_insecure', 'empty_zones_enable', 'flush_zones_on_shutdown', 'glue_cache', 'ipv4only_enable', 'match_mapped_addresses', 'memstatistics', 'message_compression', 'minimal_any', 'multi_master', 'notify_to_soa', 'provide_ixfr', 'querylog', 'recursion', 'request_expire', 'request_ixfr', 'request_nsid', 'require_server_cookie', 'reuseport', 'root_key_sentinel', 'send_cookie', 'stale_answer_enable', 'stale_cache_enable', 'synth_from_dnssec', 'trust_anchor_telemetry', 'try_tcp_refresh', 'update_check_ksk', 'use_alt_transfer_source', 'zero_no_soa_ttl', 'zero_no_soa_ttl_cache'] %} +{{ functions.boolean_option(conf_key, value) }} + +{# --- BOOLEAN OR STRING --- #} +{% elif key in ['dialup', 'ixfr_from_differences', 'minimal_responses', 'notify', 'zone_statistics', 'dnssec_validation'] %} +{{ conf_key }} {{ functions.boolean_or_string(value) }}; + +{# --- FALLTHROUGH --- #} +{% else %} +{# Strict mode: Ignore unknown keys or warn if possible. For now, silence is safer than invalid config. #} {% endif %} -{% if item.options.sig_validity_interval is defined and item.options.sig_validity_interval %} -sig-validity-interval {{ item.options.sig_validity_interval }}; -{% endif %} -{% if item.options.tkey_dhkey is defined and item.options.tkey_dhkey is mapping %} -tkey-dhkey "{{ item.options.tkey_dhkey.key_name }}" {{ item.options.tkey_dhkey.key_tag }}; -{% endif %} -{# special_quoted_string options with reserved keywords #} -{% if item.options.dnstap_identity is defined and item.options.dnstap_identity is string %} -{{ functions.reserved_or_quoted('dnstap-identity', item.options.dnstap_identity, ['none', 'hostname']) -}} -{% endif %} -{% if item.options.dnstap_version is defined and item.options.dnstap_version is string %} -{{ functions.reserved_or_quoted('dnstap-version', item.options.dnstap_version, ['none']) -}} -{% endif %} -{% if item.options.geoip_directory is defined and item.options.geoip_directory is string %} -{{ functions.reserved_or_quoted('geoip-directory', item.options.geoip_directory, ['none']) -}} -{% endif %} -{% if item.options.hostname is defined and item.options.hostname is string %} -{{ functions.reserved_or_quoted('hostname', item.options.hostname, ['none']) -}} -{% endif %} -{% if item.options.lock_file is defined and item.options.lock_file is string %} -{{ functions.reserved_or_quoted('lock-file', item.options.lock_file, ['none']) -}} -{% endif %} -{% if item.options.pid_file is defined and item.options.pid_file is string %} -{{ functions.reserved_or_quoted('pid-file', item.options.pid_file, ['none']) -}} -{% endif %} -{% if item.options.random_device is defined and item.options.random_device is string %} -{{ functions.reserved_or_quoted('random-device', item.options.random_device, ['none']) -}} -{% endif %} -{% if item.options.server_id is defined and item.options.server_id is string %} -{{ functions.reserved_or_quoted('server-id', item.options.server_id, ['none', 'hostname']) -}} -{% endif %} -{% if item.options.session_keyfile is defined and item.options.session_keyfile is string %} -{{ functions.reserved_or_quoted('session-keyfile', item.options.session_keyfile, ['none']) -}} -{% endif %} -{% if item.options.version is defined and item.options.version is string %} -{{ functions.reserved_or_quoted('version', item.options.version, ['none']) -}} -{% endif %} -{# simple list options #} -{{ ('avoid-v4-udp-ports {\n' + functions.simple_item_list(item.options.avoid_v4_udp_ports) + '};\n') if item.options.avoid_v4_udp_ports is defined and item.options.avoid_v4_udp_ports -}} -{{ ('avoid-v6-udp-ports {\n' + functions.simple_item_list(item.options.avoid_v6_udp_ports) + '};\n') if item.options.avoid_v6_udp_ports is defined and item.options.avoid_v6_udp_ports -}} -{{ ('use-v4-udp-ports {\n' + functions.simple_item_list(item.options.use_v4_udp_ports) + '};\n') if item.options.use_v4_udp_ports is defined and item.options.use_v4_udp_ports -}} -{{ ('use-v6-udp-ports {\n' + functions.simple_item_list(item.options.use_v6_udp_ports) + '};\n') if item.options.use_v6_udp_ports is defined and item.options.use_v6_udp_ports -}} -{{ ('validate-except {\n' + functions.simple_item_list(item.options.validate_except) + '};\n') if item.options.validate_except is defined and item.options.validate_except -}} -{# boolean_or_string options #} -{{ ('dialup ' + functions.boolean_or_string(item.options.dialup) + ';\n') if item.options.dialup is defined -}} -{{ ('ixfr-from-differences ' + functions.boolean_or_string(item.options.ixfr_from_differences) + ';\n') if item.options.ixfr_from_differences is defined -}} -{{ ('minimal-responses ' + functions.boolean_or_string(item.options.minimal_responses) + ';\n') if item.options.minimal_responses is defined -}} -{{ ('notify ' + functions.boolean_or_string(item.options.notify) + ';\n') if item.options.notify is defined -}} -{{ ('zone-statistics ' + functions.boolean_or_string(item.options.zone_statistics) + ';\n') if item.options.zone_statistics is defined -}} -{# duration_sizeval options #} -{{ ('fstrm-set-reopen-interval ' + item.options.fstrm_set_reopen_interval | string +';\n') if item.options.fstrm_set_reopen_interval is defined and item.options.fstrm_set_reopen_interval -}} -{{ ('interface-interval ' + item.options.interface_interval | string +';\n') if item.options.interface_interval is defined and item.options.interface_interval -}} -{{ ('lame-ttl ' + item.options.lame_ttl | string +';\n') if item.options.lame_ttl is defined and item.options.lame_ttl -}} -{{ ('lmdb-mapsize ' + item.options.lmdb_mapsize | string +';\n') if item.options.lmdb_mapsize is defined and item.options.lmdb_mapsize -}} -{{ ('max-cache-ttl ' + item.options.max_cache_ttl | string +';\n') if item.options.max_cache_ttl is defined and item.options.max_cache_ttl -}} -{{ ('max-ncache-ttl ' + item.options.max_ncache_ttl | string +';\n') if item.options.max_ncache_ttl is defined and item.options.max_ncache_ttl -}} -{{ ('max-stale-ttl ' + item.options.max_stale_ttl | string +';\n') if item.options.max_stale_ttl is defined and item.options.max_stale_ttl -}} -{{ ('min-cache-ttl ' + item.options.min_cache_ttl | string +';\n') if item.options.min_cache_ttl is defined and item.options.min_cache_ttl -}} -{{ ('min-ncache-ttl ' + item.options.min_ncache_ttl | string +';\n') if item.options.min_ncache_ttl is defined and item.options.min_ncache_ttl -}} -{{ ('nta-lifetime ' + item.options.nta_lifetime | string +';\n') if item.options.nta_lifetime is defined and item.options.nta_lifetime -}} -{{ ('nta-recheck ' + item.options.nta_recheck | string +';\n') if item.options.nta_recheck is defined and item.options.nta_recheck -}} -{{ ('servfail-ttl ' + item.options.servfail_ttl | string +';\n') if item.options.servfail_ttl is defined and item.options.servfail_ttl -}} -{{ ('stale-answer-ttl ' + item.options.stale_answer_ttl | string +';\n') if item.options.stale_answer_ttl is defined and item.options.stale_answer_ttl -}} -{{ ('stale-refresh-time ' + item.options.stale_refresh_time | string +';\n') if item.options.stale_refresh_time is defined and item.options.stale_refresh_time -}} -{# special options options #} -{{ ('auto-dnssec ' + item.options.auto_dnssec | string +';\n') if item.options.auto_dnssec is defined and item.options.auto_dnssec -}} -{{ ('check-dup-records ' + item.options.check_dup_records | string +';\n') if item.options.check_dup_records is defined and item.options.check_dup_records -}} -{{ ('check-mx ' + item.options.check_mx | string +';\n') if item.options.check_mx is defined and item.options.check_mx -}} -{{ ('check-mx-cname ' + item.options.check_mx_cname | string +';\n') if item.options.check_mx_cname is defined and item.options.check_mx_cname -}} -{{ ('check-spf ' + item.options.check_spf | string +';\n') if item.options.check_spf is defined and item.options.check_spf -}} -{{ ('check-srv-cname ' + item.options.check_srv_cname | string +';\n') if item.options.check_srv_cname is defined and item.options.check_srv_cname -}} -{{ ('cookie-algorithm ' + item.options.cookie_algorithm | string +';\n') if item.options.cookie_algorithm is defined and item.options.cookie_algorithm -}} -{{ ('coresize ' + item.options.coresize | string +';\n') if item.options.coresize is defined and item.options.coresize -}} -{{ ('datasize ' + item.options.datasize | string +';\n') if item.options.datasize is defined and item.options.datasize -}} -{{ ('dnssec-update-mode ' + item.options.dnssec_update_mode | string +';\n') if item.options.dnssec_update_mode is defined and item.options.dnssec_update_mode -}} -{{ ('dnssec-validation ' + functions.boolean_or_string(item.options.dnssec_validation) +';\n') if item.options.dnssec_validation is defined -}} -{{ ('files ' + item.options.files | string +';\n') if item.options.files is defined and item.options.files -}} -{{ ('forward ' + item.options.forward | string +';\n') if item.options.forward is defined and item.options.forward -}} -{{ ('fstrm-set-output-queue-model ' + item.options.fstrm_set_output_queue_model | string +';\n') if item.options.fstrm_set_output_queue_model is defined and item.options.fstrm_set_output_queue_model -}} -{{ ('masterfile-format ' + item.options.masterfile_format | string +';\n') if item.options.masterfile_format is defined and item.options.masterfile_format -}} -{{ ('masterfile-style ' + item.options.masterfile_style | string +';\n') if item.options.masterfile_style is defined and item.options.masterfile_style -}} -{{ ('max-cache-size ' + item.options.max_cache_size | string +';\n') if item.options.max_cache_size is defined and item.options.max_cache_size -}} -{{ ('max-ixfr-ratio ' + item.options.max_ixfr_ratio | string +';\n') if item.options.max_ixfr_ratio is defined and item.options.max_ixfr_ratio -}} -{{ ('max-journal-size ' + item.options.max_journal_size | string +';\n') if item.options.max_journal_size is defined and item.options.max_journal_size -}} -{{ ('max-zone-ttl ' + item.options.max_zone_ttl | string +';\n') if item.options.max_zone_ttl is defined and item.options.max_zone_ttl -}} -{{ ('qname-minimization ' + item.options.qname_minimization | string +';\n') if item.options.qname_minimization is defined and item.options.qname_minimization -}} -{{ ('serial-update-method ' + item.options.serial_update_method | string +';\n') if item.options.serial_update_method is defined and item.options.serial_update_method -}} -{{ ('stacksize ' + item.options.stacksize | string +';\n') if item.options.stacksize is defined and item.options.stacksize -}} -{{ ('stale-answer-client-timeout ' + item.options.stale_answer_client_timeout | string +';\n') if item.options.stale_answer_client_timeout is defined and item.options.stale_answer_client_timeout -}} -{{ ('transfer-format ' + item.options.transfer_format | string +';\n') if item.options.transfer_format is defined and item.options.transfer_format -}} -{# quoted_string options #} -{{ ('bindkeys-file "' + item.options.bindkeys_file | string +'";\n') if item.options.bindkeys_file is defined and item.options.bindkeys_file -}} -{{ ('directory "' + item.options.directory | string +'";\n') if item.options.directory is defined and item.options.directory -}} -{{ ('dump-file "' + item.options.dump_file | string +'";\n') if item.options.dump_file is defined and item.options.dump_file -}} -{{ ('key-directory "' + item.options.key_directory | string +'";\n') if item.options.key_directory is defined and item.options.key_directory -}} -{{ ('managed-keys-directory "' + item.options.managed_keys_directory | string +'";\n') if item.options.managed_keys_directory is defined and item.options.managed_keys_directory -}} -{{ ('memstatistics-file "' + item.options.memstatistics_file | string +'";\n') if item.options.memstatistics_file is defined and item.options.memstatistics_file -}} -{{ ('new-zones-directory "' + item.options.new_zones_directory | string +'";\n') if item.options.new_zones_directory is defined and item.options.new_zones_directory -}} -{{ ('recursing-file "' + item.options.recursing_file | string +'";\n') if item.options.recursing_file is defined and item.options.recursing_file -}} -{{ ('secroots-file "' + item.options.secroots_file | string +'";\n') if item.options.secroots_file is defined and item.options.secroots_file -}} -{{ ('statistics-file "' + item.options.statistics_file | string +'";\n') if item.options.statistics_file is defined and item.options.statistics_file -}} -{{ ('tkey-domain "' + item.options.tkey_domain | string +'";\n') if item.options.tkey_domain is defined and item.options.tkey_domain -}} -{{ ('tkey-gssapi-credential "' + item.options.tkey_gssapi_credential | string +'";\n') if item.options.tkey_gssapi_credential is defined and item.options.tkey_gssapi_credential -}} -{{ ('tkey-gssapi-keytab "' + item.options.tkey_gssapi_keytab | string +'";\n') if item.options.tkey_gssapi_keytab is defined and item.options.tkey_gssapi_keytab -}} -{# simple_item_list options #} -{{ ('allow-notify {\n' + functions.simple_item_list(item.options.allow_notify) + '};\n') if item.options.allow_notify is defined and item.options.allow_notify -}} -{{ ('allow-query {\n' + functions.simple_item_list(item.options.allow_query) + '};\n') if item.options.allow_query is defined and item.options.allow_query -}} -{{ ('allow-query-cache {\n' + functions.simple_item_list(item.options.allow_query_cache) + '};\n') if item.options.allow_query_cache is defined and item.options.allow_query_cache -}} -{{ ('allow-query-cache-on {\n' + functions.simple_item_list(item.options.allow_query_cache_on) + '};\n') if item.options.allow_query_cache_on is defined and item.options.allow_query_cache_on -}} -{{ ('allow-query-on {\n' + functions.simple_item_list(item.options.allow_query_on) + '};\n') if item.options.allow_query_on is defined and item.options.allow_query_on -}} -{{ ('allow-recursion {\n' + functions.simple_item_list(item.options.allow_recursion) + '};\n') if item.options.allow_recursion is defined and item.options.allow_recursion -}} -{{ ('allow-recursion-on {\n' + functions.simple_item_list(item.options.allow_recursion_on) + '};\n') if item.options.allow_recursion_on is defined and item.options.allow_recursion_on -}} -{{ ('allow-update {\n' + functions.simple_item_list(item.options.allow_update) + '};\n') if item.options.allow_update is defined and item.options.allow_update -}} -{{ ('allow-update-forwarding {\n' + functions.simple_item_list(item.options.allow_update_forwarding) + '};\n') if item.options.allow_update_forwarding is defined and item.options.allow_update_forwarding -}} -{{ ('blackhole {\n' + functions.simple_item_list(item.options.blackhole) + '};\n') if item.options.blackhole is defined and item.options.blackhole -}} -{{ ('keep-response-order {\n' + functions.simple_item_list(item.options.keep_response_order) + '};\n') if item.options.keep_response_order is defined and item.options.keep_response_order -}} -{{ ('no-case-compress {\n' + functions.simple_item_list(item.options.no_case_compress) + '};\n') if item.options.no_case_compress is defined and item.options.no_case_compress -}} -{{ ('sortlist {\n' + functions.simple_item_list(item.options.sortlist) + '};\n') if item.options.sortlist is defined and item.options.sortlist -}} -{# String options #} -{{ ('attach-cache ' + item.options.attach_cache | string +';\n') if item.options.attach_cache is defined and item.options.attach_cache -}} -{{ ('cookie-secret ' + item.options.cookie_secret | string +';\n') if item.options.cookie_secret is defined and item.options.cookie_secret -}} -{{ ('disable-empty-zone ' + item.options.disable_empty_zone | string +';\n') if item.options.disable_empty_zone is defined and item.options.disable_empty_zone -}} -{{ ('dns64-contact ' + item.options.dns64_contact | string +';\n') if item.options.dns64_contact is defined and item.options.dns64_contact -}} -{{ ('dns64-server ' + item.options.dns64_server | string +';\n') if item.options.dns64_server is defined and item.options.dns64_server -}} -{{ ('dnssec-policy ' + item.options.dnssec_policy | string +';\n') if item.options.dnssec_policy is defined and item.options.dnssec_policy -}} -{{ ('empty-contact ' + item.options.empty_contact | string +';\n') if item.options.empty_contact is defined and item.options.empty_contact -}} -{{ ('empty-server ' + item.options.empty_server | string +';\n') if item.options.empty_server is defined and item.options.empty_server -}} -{{ ('ipv4only-contact ' + item.options.ipv4only_contact | string +';\n') if item.options.ipv4only_contact is defined and item.options.ipv4only_contact -}} -{{ ('ipv4only-server ' + item.options.ipv4only_server | string +';\n') if item.options.ipv4only_server is defined and item.options.ipv4only_server -}} -{{ ('nxdomain-redirect ' + item.options.nxdomain_redirect | string +';\n') if item.options.nxdomain_redirect is defined and item.options.nxdomain_redirect -}} -{{ ('preferred-glue ' + item.options.preferred_glue | string +';\n') if item.options.preferred_glue is defined and item.options.preferred_glue -}} -{{ ('session-keyalg ' + item.options.session_keyalg | string +';\n') if item.options.session_keyalg is defined and item.options.session_keyalg -}} -{{ ('session-keyname ' + item.options.session_keyname | string +';\n') if item.options.session_keyname is defined and item.options.session_keyname -}} -{# Integer options #} -{{ ('clients-per-query ' + item.options.clients_per_query | string +';\n') if item.options.clients_per_query is defined and item.options.clients_per_query -}} -{{ ('dnskey-sig-validity ' + item.options.dnskey_sig_validity | string +';\n') if item.options.dnskey_sig_validity is defined and item.options.dnskey_sig_validity -}} -{{ ('dnssec-loadkeys-interval ' + item.options.dnssec_loadkeys_interval | string +';\n') if item.options.dnssec_loadkeys_interval is defined and item.options.dnssec_loadkeys_interval -}} -{{ ('dscp ' + item.options.dscp | string +';\n') if item.options.dscp is defined and item.options.dscp -}} -{{ ('edns-udp-size ' + item.options.edns_udp_size | string +';\n') if item.options.edns_udp_size is defined and item.options.edns_udp_size -}} -{{ ('fstrm-set-buffer-hint ' + item.options.fstrm_set_buffer_hint | string +';\n') if item.options.fstrm_set_buffer_hint is defined and item.options.fstrm_set_buffer_hint -}} -{{ ('fstrm-set-flush-timeout ' + item.options.fstrm_set_flush_timeout | string +';\n') if item.options.fstrm_set_flush_timeout is defined and item.options.fstrm_set_flush_timeout -}} -{{ ('fstrm-set-input-queue-size ' + item.options.fstrm_set_input_queue_size | string +';\n') if item.options.fstrm_set_input_queue_size is defined and item.options.fstrm_set_input_queue_size -}} -{{ ('fstrm-set-output-notify-threshold ' + item.options.fstrm_set_output_notify_threshold | string +';\n') if item.options.fstrm_set_output_notify_threshold is defined and item.options.fstrm_set_output_notify_threshold -}} -{{ ('fstrm-set-output-queue-size ' + item.options.fstrm_set_output_queue_size | string +';\n') if item.options.fstrm_set_output_queue_size is defined and item.options.fstrm_set_output_queue_size -}} -{{ ('heartbeat-interval ' + item.options.heartbeat_interval | string +';\n') if item.options.heartbeat_interval is defined and item.options.heartbeat_interval -}} -{{ ('http-listener-clients ' + item.options.http_listener_clients | string +';\n') if item.options.http_listener_clients is defined and item.options.http_listener_clients -}} -{{ ('http-port ' + item.options.http_port | string +';\n') if item.options.http_port is defined and item.options.http_port -}} -{{ ('http-streams-per-connection ' + item.options.http_streams_per_connection | string +';\n') if item.options.http_streams_per_connection is defined and item.options.http_streams_per_connection -}} -{{ ('https-port ' + item.options.https_port | string +';\n') if item.options.https_port is defined and item.options.https_port -}} -{{ ('max-clients-per-query ' + item.options.max_clients_per_query | string +';\n') if item.options.max_clients_per_query is defined and item.options.max_clients_per_query -}} -{{ ('max-records ' + item.options.max_records | string +';\n') if item.options.max_records is defined and item.options.max_records -}} -{{ ('max-recursion-depth ' + item.options.max_recursion_depth | string +';\n') if item.options.max_recursion_depth is defined and item.options.max_recursion_depth -}} -{{ ('max-recursion-queries ' + item.options.max_recursion_queries | string +';\n') if item.options.max_recursion_queries is defined and item.options.max_recursion_queries -}} -{{ ('max-refresh-time ' + item.options.max_refresh_time | string +';\n') if item.options.max_refresh_time is defined and item.options.max_refresh_time -}} -{{ ('max-retry-time ' + item.options.max_retry_time | string +';\n') if item.options.max_retry_time is defined and item.options.max_retry_time -}} -{{ ('max-rsa-exponent-size ' + item.options.max_rsa_exponent_size | string +';\n') if item.options.max_rsa_exponent_size is defined and item.options.max_rsa_exponent_size -}} -{{ ('max-transfer-idle-in ' + item.options.max_transfer_idle_in | string +';\n') if item.options.max_transfer_idle_in is defined and item.options.max_transfer_idle_in -}} -{{ ('max-transfer-idle-out ' + item.options.max_transfer_idle_out | string +';\n') if item.options.max_transfer_idle_out is defined and item.options.max_transfer_idle_out -}} -{{ ('max-transfer-time-in ' + item.options.max_transfer_time_in | string +';\n') if item.options.max_transfer_time_in is defined and item.options.max_transfer_time_in -}} -{{ ('max-transfer-time-out ' + item.options.max_transfer_time_out | string +';\n') if item.options.max_transfer_time_out is defined and item.options.max_transfer_time_out -}} -{{ ('max-udp-size ' + item.options.max_udp_size | string +';\n') if item.options.max_udp_size is defined and item.options.max_udp_size -}} -{{ ('min-refresh-time ' + item.options.min_refresh_time | string +';\n') if item.options.min_refresh_time is defined and item.options.min_refresh_time -}} -{{ ('min-retry-time ' + item.options.min_retry_time | string +';\n') if item.options.min_retry_time is defined and item.options.min_retry_time -}} -{{ ('nocookie-udp-size ' + item.options.nocookie_udp_size | string +';\n') if item.options.nocookie_udp_size is defined and item.options.nocookie_udp_size -}} -{{ ('notify-delay ' + item.options.notify_delay | string +';\n') if item.options.notify_delay is defined and item.options.notify_delay -}} -{{ ('notify-rate ' + item.options.notify_rate | string +';\n') if item.options.notify_rate is defined and item.options.notify_rate -}} -{{ ('port ' + item.options.port | string +';\n') if item.options.port is defined and item.options.port -}} -{{ ('recursive-clients ' + item.options.recursive_clients | string +';\n') if item.options.recursive_clients is defined and item.options.recursive_clients -}} -{{ ('resolver-nonbackoff-tries ' + item.options.resolver_nonbackoff_tries | string +';\n') if item.options.resolver_nonbackoff_tries is defined and item.options.resolver_nonbackoff_tries -}} -{{ ('resolver-query-timeout ' + item.options.resolver_query_timeout | string +';\n') if item.options.resolver_query_timeout is defined and item.options.resolver_query_timeout -}} -{{ ('resolver-retry-interval ' + item.options.resolver_retry_interval | string +';\n') if item.options.resolver_retry_interval is defined and item.options.resolver_retry_interval -}} -{{ ('serial-query-rate ' + item.options.serial_query_rate | string +';\n') if item.options.serial_query_rate is defined and item.options.serial_query_rate -}} -{{ ('sig-signing-nodes ' + item.options.sig_signing_nodes | string +';\n') if item.options.sig_signing_nodes is defined and item.options.sig_signing_nodes -}} -{{ ('sig-signing-signatures ' + item.options.sig_signing_signatures | string +';\n') if item.options.sig_signing_signatures is defined and item.options.sig_signing_signatures -}} -{{ ('sig-signing-type ' + item.options.sig_signing_type | string +';\n') if item.options.sig_signing_type is defined and item.options.sig_signing_type -}} -{{ ('startup-notify-rate ' + item.options.startup_notify_rate | string +';\n') if item.options.startup_notify_rate is defined and item.options.startup_notify_rate -}} -{{ ('tcp-advertised-timeout ' + item.options.tcp_advertised_timeout | string +';\n') if item.options.tcp_advertised_timeout is defined and item.options.tcp_advertised_timeout -}} -{{ ('tcp-clients ' + item.options.tcp_clients | string +';\n') if item.options.tcp_clients is defined and item.options.tcp_clients -}} -{{ ('tcp-idle-timeout ' + item.options.tcp_idle_timeout | string +';\n') if item.options.tcp_idle_timeout is defined and item.options.tcp_idle_timeout -}} -{{ ('tcp-initial-timeout ' + item.options.tcp_initial_timeout | string +';\n') if item.options.tcp_initial_timeout is defined and item.options.tcp_initial_timeout -}} -{{ ('tcp-keepalive-timeout ' + item.options.tcp_keepalive_timeout | string +';\n') if item.options.tcp_keepalive_timeout is defined and item.options.tcp_keepalive_timeout -}} -{{ ('tcp-listen-queue ' + item.options.tcp_listen_queue | string +';\n') if item.options.tcp_listen_queue is defined and item.options.tcp_listen_queue -}} -{{ ('tcp-receive-buffer ' + item.options.tcp_receive_buffer | string +';\n') if item.options.tcp_receive_buffer is defined and item.options.tcp_receive_buffer -}} -{{ ('tcp-send-buffer ' + item.options.tcp_send_buffer | string +';\n') if item.options.tcp_send_buffer is defined and item.options.tcp_send_buffer -}} -{{ ('tls-port ' + item.options.tls_port | string +';\n') if item.options.tls_port is defined and item.options.tls_port -}} -{{ ('transfer-message-size ' + item.options.transfer_message_size | string +';\n') if item.options.transfer_message_size is defined and item.options.transfer_message_size -}} -{{ ('transfers-in ' + item.options.transfers_in | string +';\n') if item.options.transfers_in is defined and item.options.transfers_in -}} -{{ ('transfers-out ' + item.options.transfers_out | string +';\n') if item.options.transfers_out is defined and item.options.transfers_out -}} -{{ ('transfers-per-ns ' + item.options.transfers_per_ns | string +';\n') if item.options.transfers_per_ns is defined and item.options.transfers_per_ns -}} -{{ ('udp-receive-buffer ' + item.options.udp_receive_buffer | string +';\n') if item.options.udp_receive_buffer is defined and item.options.udp_receive_buffer -}} -{{ ('udp-send-buffer ' + item.options.udp_send_buffer | string +';\n') if item.options.udp_send_buffer is defined and item.options.udp_send_buffer -}} -{{ ('v6-bias ' + item.options.v6_bias | string +';\n') if item.options.v6_bias is defined and item.options.v6_bias -}} -{# Boolean options #} -{{ (functions.boolean_option('allow-new-zones', item.options.allow_new_zones) + '\n') if item.options.allow_new_zones is defined -}} -{{ (functions.boolean_option('answer-cookie', item.options.answer_cookie) + '\n') if item.options.answer_cookie is defined -}} -{{ (functions.boolean_option('auth-nxdomain', item.options.auth_nxdomain) + '\n') if item.options.auth_nxdomain is defined -}} -{{ (functions.boolean_option('automatic-interface-scan', item.options.automatic_interface_scan) + '\n') if item.options.automatic_interface_scan is defined -}} -{{ (functions.boolean_option('check-integrity', item.options.check_integrity) + '\n') if item.options.check_integrity is defined -}} -{{ (functions.boolean_option('check-sibling', item.options.check_sibling) + '\n') if item.options.check_sibling is defined -}} -{{ (functions.boolean_option('check-wildcard', item.options.check_wildcard) + '\n') if item.options.check_wildcard is defined -}} -{{ (functions.boolean_option('dnsrps-enable', item.options.dnsrps_enable) + '\n') if item.options.dnsrps_enable is defined -}} -{{ (functions.boolean_option('dnssec-accept-expired', item.options.dnssec_accept_expired) + '\n') if item.options.dnssec_accept_expired is defined -}} -{{ (functions.boolean_option('dnssec-dnskey-kskonly', item.options.dnssec_dnskey_kskonly) + '\n') if item.options.dnssec_dnskey_kskonly is defined -}} -{{ (functions.boolean_option('dnssec-secure-to-insecure', item.options.dnssec_secure_to_insecure) + '\n') if item.options.dnssec_secure_to_insecure is defined -}} -{{ (functions.boolean_option('empty-zones-enable', item.options.empty_zones_enable) + '\n') if item.options.empty_zones_enable is defined -}} -{{ (functions.boolean_option('flush-zones-on-shutdown', item.options.flush_zones_on_shutdown) + '\n') if item.options.flush_zones_on_shutdown is defined -}} -{{ (functions.boolean_option('glue-cache', item.options.glue_cache) + '\n') if item.options.glue_cache is defined -}} -{{ (functions.boolean_option('ipv4only-enable', item.options.ipv4only_enable) + '\n') if item.options.ipv4only_enable is defined -}} -{{ (functions.boolean_option('match-mapped-addresses', item.options.match_mapped_addresses) + '\n') if item.options.match_mapped_addresses is defined -}} -{{ (functions.boolean_option('memstatistics', item.options.memstatistics) + '\n') if item.options.memstatistics is defined -}} -{{ (functions.boolean_option('message-compression', item.options.message_compression) + '\n') if item.options.message_compression is defined -}} -{{ (functions.boolean_option('minimal-any', item.options.minimal_any) + '\n') if item.options.minimal_any is defined -}} -{{ (functions.boolean_option('multi-master', item.options.multi_master) + '\n') if item.options.multi_master is defined -}} -{{ (functions.boolean_option('notify-to-soa', item.options.notify_to_soa) + '\n') if item.options.notify_to_soa is defined -}} -{{ (functions.boolean_option('provide-ixfr', item.options.provide_ixfr) + '\n') if item.options.provide_ixfr is defined -}} -{{ (functions.boolean_option('querylog', item.options.querylog) + '\n') if item.options.querylog is defined -}} -{{ (functions.boolean_option('recursion', item.options.recursion) + '\n') if item.options.recursion is defined -}} -{{ (functions.boolean_option('request-expire', item.options.request_expire) + '\n') if item.options.request_expire is defined -}} -{{ (functions.boolean_option('request-ixfr', item.options.request_ixfr) + '\n') if item.options.request_ixfr is defined -}} -{{ (functions.boolean_option('request-nsid', item.options.request_nsid) + '\n') if item.options.request_nsid is defined -}} -{{ (functions.boolean_option('require-server-cookie', item.options.require_server_cookie) + '\n') if item.options.require_server_cookie is defined -}} -{{ (functions.boolean_option('reuseport', item.options.reuseport) + '\n') if item.options.reuseport is defined -}} -{{ (functions.boolean_option('root-key-sentinel', item.options.root_key_sentinel) + '\n') if item.options.root_key_sentinel is defined -}} -{{ (functions.boolean_option('send-cookie', item.options.send_cookie) + '\n') if item.options.send_cookie is defined -}} -{{ (functions.boolean_option('stale-answer-enable', item.options.stale_answer_enable) + '\n') if item.options.stale_answer_enable is defined -}} -{{ (functions.boolean_option('stale-cache-enable', item.options.stale_cache_enable) + '\n') if item.options.stale_cache_enable is defined -}} -{{ (functions.boolean_option('synth-from-dnssec', item.options.synth_from_dnssec) + '\n') if item.options.synth_from_dnssec is defined -}} -{{ (functions.boolean_option('trust-anchor-telemetry', item.options.trust_anchor_telemetry) + '\n') if item.options.trust_anchor_telemetry is defined -}} -{{ (functions.boolean_option('try-tcp-refresh', item.options.try_tcp_refresh) + '\n') if item.options.try_tcp_refresh is defined -}} -{{ (functions.boolean_option('update-check-ksk', item.options.update_check_ksk) + '\n') if item.options.update_check_ksk is defined -}} -{{ (functions.boolean_option('use-alt-transfer-source', item.options.use_alt_transfer_source) + '\n') if item.options.use_alt_transfer_source is defined -}} -{{ (functions.boolean_option('zero-no-soa-ttl', item.options.zero_no_soa_ttl) + '\n') if item.options.zero_no_soa_ttl is defined -}} -{{ (functions.boolean_option('zero-no-soa-ttl-cache', item.options.zero_no_soa_ttl_cache) + '\n') if item.options.zero_no_soa_ttl_cache is defined -}} + +{% endfor %} {% endfilter %} }; - diff --git a/templates/named.conf.zone.j2 b/templates/named.conf.zone.j2 index 0423220..e73704a 100644 --- a/templates/named.conf.zone.j2 +++ b/templates/named.conf.zone.j2 @@ -2,29 +2,20 @@ zone "{{ zone.name }}" { {% filter indent(bind9_config_indent, true) %} -# Zone {{ zone.name }} type {{ zone.type }} -{# Most critical/defining statements first #} -{{ ('type ' + zone.type | string+';\n') if zone.type is defined and zone.type -}} -{{ ('file "' + zone.file | string+'";\n') if zone.file is defined and zone.file -}} -{{ ('forward ' + zone.forward | string+';\n') if zone.forward is defined and zone.forward -}} -{{ ('journal "' + zone.journal | string+'";\n') if zone.journal is defined and zone.journal -}} -{{ ('key-directory "' + zone.key_directory | string+'";\n') if zone.key_directory is defined and zone.key_directory -}} -{# boolean_or_string options #} -{{ ('dialup ' + functions.boolean_or_string(zone.dialup) + ';\n') if zone.dialup is defined -}} -{{ ('notify ' + functions.boolean_or_string(zone.notify) + ';\n') if zone.notify is defined -}} -{{ ('zone-statistics ' + functions.boolean_or_string(zone.zone_statistics) + ';\n') if zone.zone_statistics is defined -}} -{# upstream_servers options #} -{{ functions.parent_address_key_tls('also-notify', zone.also_notify) if zone.also_notify is defined and zone.also_notify -}} -{{ functions.parent_address_key_tls('primaries', zone.primaries) if zone.primaries is defined and zone.primaries -}} -{{ functions.parent_address_key_tls('parental-agents', zone.parental_agents) if zone.parental_agents is defined and zone.parental_agents -}} -{# Unicorn Options#} -{% if zone.update_policy is defined and zone.update_policy %} -{% if zone.update_policy == 'local' %} +{% for key, value in zone.items() %} +{% set conf_key = key | replace('_', '-') %} + +{% if key == 'name' %} +{# Skip name as it is in the zone header #} + +{# --- COMPLEX BLOCKS --- #} +{% elif key == 'update_policy' %} +{% if value == 'local' %} update-policy local; {% else %} update-policy { {% filter indent(bind9_config_indent, true) %} -{% for policy in zone.update_policy %} +{% for policy in value %} {{ policy.permission -}} {{ ' ' + policy.identity -}} {{ ' ' + policy.ruletype -}} @@ -33,127 +24,61 @@ update-policy { {% endfor %} {% endfilter %}}; {% endif %} -{% endif %} -{% if zone.sig_validity_interval is defined and zone.sig_validity_interval %} + +{% elif key == 'sig_validity_interval' %} sig-validity-interval -{{- (' ' + zone.sig_validity_interval.upper | string) }} -{{- (' ' + zone.sig_validity_interval.lower | string) if zone.sig_validity_interval.lower is defined and zone.sig_validity_interval.lower -}}; -{% endif %} -{% if zone.server_names is defined and zone.server_names %} -server-names { -{{ functions.simple_item_list(zone.server_names) }}}; -{% endif %} -{% if zone.server_addresses is defined and zone.server_addresses %} -server-addresses { -{{ functions.simple_item_list(zone.server_addresses) }}}; -{% endif %} -{{ functions.parent_address_port_dscp('forwarders', zone.forwarders) if zone.forwarders is defined and zone.forwarders -}} -{% if zone.allow_transfer is defined and zone.allow_transfer is not string %} +{{- (' ' + value.upper | string) }} +{{- (' ' + value.lower | string) if value.lower is defined and value.lower -}}; + +{% elif key in ['server_names', 'server_addresses'] %} +{{ conf_key }} { +{{ functions.simple_item_list(value) }}}; + +{% elif key in ['also_notify', 'primaries', 'parental_agents'] %} +{{ functions.parent_address_key_tls(conf_key, value) -}} + +{% elif key == 'forwarders' %} +{{ functions.parent_address_port_dscp('forwarders', value) -}} + +{% elif key == 'allow_transfer' and value is not string and value is mapping %} allow-transfer -{{- (' port ' + zone.allow_transfer.port | string) if zone.allow_transfer.port is defined and zone.allow_transfer.port -}} -{{- (' transport ' + zone.allow_transfer.transport) if zone.allow_transfer.transport is defined and zone.allow_transfer.transport }} { -{{ functions.simple_item_list(zone.allow_transfer.addresses) }}}; +{{- (' port ' + value.port | string) if value.port is defined and value.port -}} +{{- (' transport ' + value.transport) if value.transport is defined and value.transport }} { +{{ functions.simple_item_list(value.addresses) }}}; + +{% elif key in ['transfer_source', 'transfer_source_v6', 'alt_transfer_source', 'alt_transfer_source_v6', 'notify_source', 'notify_source_v6', 'parental_source', 'parental_source_v6'] %} +{{ conf_key }} {{ value.address -}} +{{- (' port ' + value.port | string) if value.port is defined and value.port -}} +{{- (' dscp ' + value.dscp | string) if value.dscp is defined and value.dscp }}; + +{# --- SIMPLE LISTS --- #} +{% elif key in ['allow_notify', 'allow_query', 'allow_query_on', 'allow_update', 'allow_update_forwarding'] %} +{{ conf_key }} { +{{ functions.simple_item_list(value) }}}; + +{# --- BOOLEANS --- #} +{% elif key in ['check_integrity', 'check_sibling', 'check_wildcard', 'delegation_only', 'dnssec_dnskey_kskonly', 'dnssec_secure_to_insecure', 'inline_signing', 'ixfr_from_differences', 'multi_master', 'notify_to_soa', 'request_expire', 'request_ixfr', 'try_tcp_refresh', 'update_check_ksk', 'use_alt_transfer_source', 'zero_no_soa_ttl'] %} +{{ (functions.boolean_option(conf_key, value)) }} + +{# --- BOOLEAN OR STRING --- #} +{% elif key in ['dialup', 'notify', 'zone_statistics'] %} +{{ conf_key }} {{ functions.boolean_or_string(value) }}; + +{# --- QUOTED STRINGS --- #} +{% elif key in ['file', 'journal', 'key_directory'] %} +{{ conf_key }} "{{ value }}"; + +{# --- DEPRECATED --- #} +{% elif key == 'auto_dnssec' %} +/* WARN: auto-dnssec is removed in BIND 9.20 */ +{{ conf_key }} {{ value }}; + +{# --- FALLTHROUGH --- #} +{% else %} +{# Strict mode: Ignore unknown keys #} {% endif %} -{# simple_list options #} -{{ ('allow-notify {\n' + functions.simple_item_list(zone.allow_notify) + '};\n') if zone.allow_notify is defined and zone.allow_notify -}} -{{ ('allow-query {\n' + functions.simple_item_list(zone.allow_query) + '};\n') if zone.allow_query is defined and zone.allow_query -}} -{{ ('allow-query-on {\n' + functions.simple_item_list(zone.allow_query_on) + '};\n') if zone.allow_query_on is defined and zone.allow_query_on -}} -{{ ('allow-update {\n' + functions.simple_item_list(zone.allow_update) + '};\n') if zone.allow_update is defined and zone.allow_update -}} -{{ ('allow-update-forwarding {\n' + functions.simple_item_list(zone.allow_update_forwarding) + '};\n') if zone.allow_update_forwarding is defined and zone.allow_update_forwarding -}} -{# ip_port_dscp options#} -{% if zone.transfer_source is defined and zone.transfer_source is mapping %} -transfer-source {{ zone.transfer_source.address -}} -{{- (' port ' + zone.transfer_source.port | string) if zone.transfer_source.port is defined and zone.transfer_source.port -}} -{{- (' dscp ' + zone.transfer_source.dscp | string) if zone.transfer_source.dscp is defined and zone.transfer_source.dscp }}; -{% endif %} -{% if zone.transfer_source_v6 is defined and zone.transfer_source_v6 is mapping %} -transfer-source-v6 {{ zone.transfer_source_v6.address -}} -{{- (' port ' + zone.transfer_source_v6.port | string) if zone.transfer_source_v6.port is defined and zone.transfer_source_v6.port -}} -{{- (' dscp ' + zone.transfer_source_v6.dscp | string) if zone.transfer_source_v6.dscp is defined and zone.transfer_source_v6.dscp }}; -{% endif %} -{% if zone.alt_transfer_source is defined and zone.alt_transfer_source is mapping %} -alt-transfer-source {{ zone.alt_transfer_source.address -}} -{{- (' port ' + zone.alt_transfer_source.port | string) if zone.alt_transfer_source.port is defined and zone.alt_transfer_source.port -}} -{{- (' dscp ' + zone.alt_transfer_source.dscp | string) if zone.alt_transfer_source.dscp is defined and zone.alt_transfer_source.dscp }}; -{% endif %} -{% if zone.alt_transfer_source_v6 is defined and zone.alt_transfer_source_v6 is mapping %} -alt-transfer-source-v6 {{ zone.alt_transfer_source_v6.address -}} -{{- (' port ' + zone.alt_transfer_source_v6.port | string) if zone.alt_transfer_source_v6.port is defined and zone.alt_transfer_source_v6.port -}} -{{- (' dscp ' + zone.alt_transfer_source_v6.dscp | string) if zone.alt_transfer_source_v6.dscp is defined and zone.alt_transfer_source_v6.dscp }}; -{% endif %} -{% if zone.notify_source is defined and zone.notify_source is mapping %} -notify-source {{ zone.notify_source.address -}} -{{- (' port ' + zone.notify_source.port | string) if zone.notify_source.port is defined and zone.notify_source.port -}} -{{- (' dscp ' + zone.notify_source.dscp | string) if zone.notify_source.dscp is defined and zone.notify_source.dscp }}; -{% endif %} -{% if zone.notify_source_v6 is defined and zone.notify_source_v6 is mapping %} -notify-source-v6 {{ zone.notify_source_v6.address -}} -{{- (' port ' + zone.notify_source_v6.port | string) if zone.notify_source_v6.port is defined and zone.notify_source_v6.port -}} -{{- (' dscp ' + zone.notify_source_v6.dscp | string) if zone.notify_source_v6.dscp is defined and zone.notify_source_v6.dscp }}; -{% endif %} -{% if zone.parental_source is defined and zone.parental_source is mapping %} -parental-source {{ zone.parental_source.address -}} -{{- (' port ' + zone.parental_source.port | string) if zone.parental_source.port is defined and zone.parental_source.port -}} -{{- (' dscp ' + zone.parental_source.dscp | string) if zone.parental_source.dscp is defined and zone.parental_source.dscp }}; -{% endif %} -{% if zone.parental_source_v6 is defined and zone.parental_source_v6 is mapping %} -parental-source-v6 {{ zone.parental_source_v6.address -}} -{{- (' port ' + zone.parental_source_v6.port | string) if zone.parental_source_v6.port is defined and zone.parental_source_v6.port -}} -{{- (' dscp ' + zone.parental_source_v6.dscp | string) if zone.parental_source_v6.dscp is defined and zone.parental_source_v6.dscp }}; -{% endif %} -{# integer options #} -{{ ('dnskey-sig-validity ' + zone.dnskey_sig_validity | string+';\n') if zone.dnskey_sig_validity is defined and zone.dnskey_sig_validity -}} -{{ ('dnssec-loadkeys-interval ' + zone.dnssec_loadkeys_interval | string+';\n') if zone.dnssec_loadkeys_interval is defined and zone.dnssec_loadkeys_interval -}} -{{ ('max-records ' + zone.max_records | string+';\n') if zone.max_records is defined and zone.max_records -}} -{{ ('max-refresh-time ' + zone.max_refresh_time | string+';\n') if zone.max_refresh_time is defined and zone.max_refresh_time -}} -{{ ('max-retry-time ' + zone.max_retry_time | string+';\n') if zone.max_retry_time is defined and zone.max_retry_time -}} -{{ ('max-transfer-idle-in ' + zone.max_transfer_idle_in | string+';\n') if zone.max_transfer_idle_in is defined and zone.max_transfer_idle_in -}} -{{ ('max-transfer-idle-out ' + zone.max_transfer_idle_out | string+';\n') if zone.max_transfer_idle_out is defined and zone.max_transfer_idle_out -}} -{{ ('max-transfer-time-in ' + zone.max_transfer_time_in | string+';\n') if zone.max_transfer_time_in is defined and zone.max_transfer_time_in -}} -{{ ('max-transfer-time-out ' + zone.max_transfer_time_out | string+';\n') if zone.max_transfer_time_out is defined and zone.max_transfer_time_out -}} -{{ ('min-refresh-time ' + zone.min_refresh_time | string+';\n') if zone.min_refresh_time is defined and zone.min_refresh_time -}} -{{ ('min-retry-time ' + zone.min_retry_time | string+';\n') if zone.min_retry_time is defined and zone.min_retry_time -}} -{{ ('notify-delay ' + zone.notify_delay | string+';\n') if zone.notify_delay is defined and zone.notify_delay -}} -{{ ('sig-signing-nodes ' + zone.sig_signing_nodes | string+';\n') if zone.sig_signing_nodes is defined and zone.sig_signing_nodes -}} -{{ ('sig-signing-signatures ' + zone.sig_signing_signatures | string+';\n') if zone.sig_signing_signatures is defined and zone.sig_signing_signatures -}} -{{ ('sig-signing-type ' + zone.sig_signing_type | string+';\n') if zone.sig_signing_type is defined and zone.sig_signing_type -}} -{# boolean options #} -{{ (functions.boolean_option('check-integrity', zone.check_integrity) + '\n') if zone.check_integrity is defined -}} -{{ (functions.boolean_option('check-sibling', zone.check_sibling) + '\n') if zone.check_sibling is defined -}} -{{ (functions.boolean_option('check-wildcard', zone.check_wildcard) + '\n') if zone.check_wildcard is defined -}} -{{ (functions.boolean_option('delegation-only', zone.delegation_only) + '\n') if zone.delegation_only is defined -}} -{{ (functions.boolean_option('dnssec-dnskey-kskonly', zone.dnssec_dnskey_kskonly) + '\n') if zone.dnssec_dnskey_kskonly is defined -}} -{{ (functions.boolean_option('dnssec-secure-to-insecure', zone.dnssec_secure_to_insecure) + '\n') if zone.dnssec_secure_to_insecure is defined -}} -{{ (functions.boolean_option('inline-signing', zone.inline_signing) + '\n') if zone.inline_signing is defined -}} -{{ (functions.boolean_option('ixfr-from-differences', zone.ixfr_from_differences) + '\n') if zone.ixfr_from_differences is defined -}} -{{ (functions.boolean_option('multi-master', zone.multi_master) + '\n') if zone.multi_master is defined -}} -{{ (functions.boolean_option('notify-to-soa', zone.notify_to_soa) + '\n') if zone.notify_to_soa is defined -}} -{{ (functions.boolean_option('request-expire', zone.request_expire) + '\n') if zone.request_expire is defined -}} -{{ (functions.boolean_option('request-ixfr', zone.request_ixfr) + '\n') if zone.request_ixfr is defined -}} -{{ (functions.boolean_option('try-tcp-refresh', zone.try_tcp_refresh) + '\n') if zone.try_tcp_refresh is defined -}} -{{ (functions.boolean_option('update-check-ksk', zone.update_check_ksk) + '\n') if zone.update_check_ksk is defined -}} -{{ (functions.boolean_option('use-alt-transfer-source', zone.use_alt_transfer_source) + '\n') if zone.use_alt_transfer_source is defined -}} -{{ (functions.boolean_option('zero-no-soa-ttl', zone.zero_no_soa_ttl) + '\n') if zone.zero_no_soa_ttl is defined -}} -{# multiple_choice options #} -{{ ('auto-dnssec ' + zone.auto_dnssec | string+';\n') if zone.auto_dnssec is defined and zone.auto_dnssec -}} -{{ ('check-dup-records ' + zone.check_dup_records | string+';\n') if zone.check_dup_records is defined and zone.check_dup_records -}} -{{ ('check-mx-cname ' + zone.check_mx_cname | string+';\n') if zone.check_mx_cname is defined and zone.check_mx_cname -}} -{{ ('check-mx ' + zone.check_mx | string+';\n') if zone.check_mx is defined and zone.check_mx -}} -{{ ('check-names ' + zone.check_names | string+';\n') if zone.check_names is defined and zone.check_names -}} -{{ ('check-spf ' + zone.check_spf | string+';\n') if zone.check_spf is defined and zone.check_spf -}} -{{ ('check-srv-cname ' + zone.check_srv_cname | string+';\n') if zone.check_srv_cname is defined and zone.check_srv_cname -}} -{{ ('dnssec-update-mode ' + zone.dnssec_update_mode | string+';\n') if zone.dnssec_update_mode is defined and zone.dnssec_update_mode -}} -{{ ('masterfile-format ' + zone.masterfile_format | string+';\n') if zone.masterfile_format is defined and zone.masterfile_format -}} -{{ ('masterfile-style ' + zone.masterfile_style | string+';\n') if zone.masterfile_style is defined and zone.masterfile_style -}} -{{ ('max-ixfr-ratio ' + zone.max_ixfr_ratio | string+';\n') if zone.max_ixfr_ratio is defined and zone.max_ixfr_ratio -}} -{{ ('max-journal-size ' + zone.max_journal_size | string+';\n') if zone.max_journal_size is defined and zone.max_journal_size -}} -{{ ('max-zone-ttl ' + zone.max_zone_ttl | string+';\n') if zone.max_zone_ttl is defined and zone.max_zone_ttl -}} -{{ ('serial-update-method ' + zone.serial_update_method | string+';\n') if zone.serial_update_method is defined and zone.serial_update_method -}} -{# string options #} -{{ ('database ' + zone.database | string+';\n') if zone.database is defined and zone.database -}} -{{ ('dlz ' + zone.dlz | string+';\n') if zone.dlz is defined and zone.dlz -}} -{{ ('dnssec-policy ' + zone.dnssec_policy | string+';\n') if zone.dnssec_policy is defined and zone.dnssec_policy -}} -{{ ('in-view ' + zone.in_view | string+';\n') if zone.in_view is defined and zone.in_view -}} + +{% endfor %} {% endfilter %} }; {% endfor %} From bc7528d5d6536bad9212b8cd5b6c1570f63a15a0 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Sun, 7 Dec 2025 20:24:22 +0100 Subject: [PATCH 03/11] refactor: Rename leaf config to site config feat: Add argument specs and atomic validation --- README.md | 6 ++-- defaults/main.yml | 4 +-- meta/argument_specs.yml | 55 +++++++++++++++++++++++++++++++ tasks/main.yml | 73 ++++++++++++++++++++++++++++++++++------- 4 files changed, 121 insertions(+), 17 deletions(-) create mode 100644 meta/argument_specs.yml diff --git a/README.md b/README.md index 8c5f727..cb92179 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ named.conf bind configuration is set through the various bind9_*_config parameters. These are, in order of precedence: 1. bind9_default_config 2. bind9_group_config -3. bind9_leaf_config +3. bind9_site_config 4. bind9_host_config All these configuration parameters are merged in a way where each successing config supercedes the previous one at a config-file level. To illustrate: @@ -59,7 +59,7 @@ bind9_group_config: - name: "." type: mirror -bind9_leaf_config: +bind9_site_config: - name: named.conf.local zone: - name: "." @@ -81,7 +81,7 @@ bind9_config: file: /etc/share/dns/root.hints ``` -The `named.conf.options` block in `bind9_default_config` got completely overwritten by the `bind9_group_config`, and the `bind9_leaf_config` completely overwrote `named.conf.local`, however, `named.conf.options` was left intact after merging with `bind9_leaf_config`. +The `named.conf.options` block in `bind9_default_config` got completely overwritten by the `bind9_group_config`, and the `bind9_site_config` completely overwrote `named.conf.local`, however, `named.conf.options` was left intact after merging with `bind9_site_config`. Configuration Grammar --------------------- diff --git a/defaults/main.yml b/defaults/main.yml index 42c96d6..34ba28d 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -14,7 +14,7 @@ bind9_debug_config: false bind9_config_indent: 4 bind9_group_config: [] -bind9_leaf_config: [] +bind9_site_config: [] bind9_host_config: [] bind9_default_config: @@ -30,7 +30,7 @@ bind9_default_config: bind9_config: "{{ [bind9_default_config, bind9_group_config, - bind9_leaf_config, + bind9_site_config, bind9_host_config] | community.general.lists_mergeby('name', recursive=true, diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml new file mode 100644 index 0000000..fac379f --- /dev/null +++ b/meta/argument_specs.yml @@ -0,0 +1,55 @@ +--- +argument_specs: + main: + short_description: The main entry point for the bind9 role. + options: + bind9_config: + type: list + elements: dict + description: + - A list of configuration dictionaries that are merged to produce the final configuration. + - Each element must have a 'name' key (filename). + bind9_default_config: + type: list + elements: dict + description: Default configuration. + bind9_group_config: + type: list + elements: dict + description: Group-level configuration. + bind9_site_config: + type: list + elements: dict + description: Site/Leaf-level configuration. + bind9_host_config: + type: list + elements: dict + description: Host-level configuration. + bind9_backup_config: + type: bool + default: true + description: Whether to backup configuration files before overwriting. + bind9_debug_config: + type: bool + default: false + description: Whether to print the merged configuration during execution. + bind9_config_indent: + type: int + default: 4 + description: Indentation level for generated configuration files. + bind9_packages: + type: list + elements: str + description: List of packages to install. + bind9_cfgdir: + type: str + description: Directory for configuration files. + bind9_working_directory: + type: str + description: Working directory for BIND. + bind9_libdir: + type: str + description: Library directory for BIND. + bind9_backup_dir: + type: str + description: Directory for backups. diff --git a/tasks/main.yml b/tasks/main.yml index d9585f0..a2dd2fa 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -18,18 +18,67 @@ mode: 0750 when: bind9_backup_config is defined and bind9_backup_config -- name: Template named.conf.generator - ansible.builtin.template: - src: named.conf.generator.j2 - dest: "{{ bind9_cfgdir }}/{{ item.name }}" - owner: root - group: bind - mode: 0640 - backup: "{{ item.backup | default('false') | bool }}" - # validate: 'named-checkconf -z -j %s' - loop: "{{ bind9_config }}" - loop_control: - label: "{{ item.name }}" +- name: Deploy and Validate Configuration + block: + - name: Create backup of current config + ansible.builtin.copy: + src: "{{ bind9_cfgdir }}/{{ item.name }}" + dest: "{{ bind9_cfgdir }}/{{ item.name }}.bak" + remote_src: true + owner: root + group: bind + mode: 0640 + failed_when: false # It's okay if the file doesn't exist yet + # We do this for every file in the loop + loop: "{{ bind9_config }}" + loop_control: + label: "{{ item.name }}" + + - name: Template named.conf.generator + ansible.builtin.template: + src: named.conf.generator.j2 + dest: "{{ bind9_cfgdir }}/{{ item.name }}" + owner: root + group: bind + mode: 0640 + loop: "{{ bind9_config }}" + loop_control: + label: "{{ item.name }}" + register: _template_result + + - name: Validate configuration using named-checkconf + ansible.builtin.command: + cmd: "named-checkconf -z {{ bind9_cfgdir }}/named.conf" + changed_when: false + + rescue: + - name: Restore configuration from backup + ansible.builtin.copy: + src: "{{ bind9_cfgdir }}/{{ item.name }}.bak" + dest: "{{ bind9_cfgdir }}/{{ item.name }}" + remote_src: true + owner: root + group: bind + mode: 0640 + loop: "{{ bind9_config }}" + loop_control: + label: "{{ item.name }}" + failed_when: false # Best effort restore + + - name: Fail due to invalid configuration + ansible.builtin.fail: + msg: "Configuration validation failed. Changes have been reverted. Check the logs for named-checkconf errors." + + always: + - name: Remove backup files + ansible.builtin.file: + path: "{{ bind9_cfgdir }}/{{ item.name }}.bak" + state: absent + loop: "{{ bind9_config }}" + loop_control: + label: "{{ item.name }}" + when: bind9_backup_config | bool is false # Keep if backup is forced, otherwise cleanup temporary atomic backup + tags: - bind9 - template From ff135cb4b50c7115de022a5b4249cb26dd2cd9ac Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Sun, 7 Dec 2025 20:28:26 +0100 Subject: [PATCH 04/11] fix: Add explicit boolean comparison for Ansible 2.12+ compatibility --- tasks/main.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tasks/main.yml b/tasks/main.yml index a2dd2fa..12df4a5 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -16,7 +16,7 @@ owner: root group: root mode: 0750 - when: bind9_backup_config is defined and bind9_backup_config + when: bind9_backup_config is defined and bind9_backup_config | bool - name: Deploy and Validate Configuration block: From 83f635de8c42a0729decb7ea51d1cc30bc31181b Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Thu, 22 Jan 2026 22:33:44 +0000 Subject: [PATCH 05/11] revert 0a8ea77c63382acf7585ac7c263dc56f6792ae84 revert Merge pull request 'feature/role-improvements' (#2) from feature/role-improvements into main Reviewed-on: https://gitea/daniel/ansible-bind9-role/pulls/2 --- README.md | 6 ++-- defaults/main.yml | 4 +-- meta/argument_specs.yml | 55 ------------------------------ tasks/main.yml | 75 +++++++---------------------------------- 4 files changed, 18 insertions(+), 122 deletions(-) delete mode 100644 meta/argument_specs.yml diff --git a/README.md b/README.md index cb92179..8c5f727 100644 --- a/README.md +++ b/README.md @@ -38,7 +38,7 @@ named.conf bind configuration is set through the various bind9_*_config parameters. These are, in order of precedence: 1. bind9_default_config 2. bind9_group_config -3. bind9_site_config +3. bind9_leaf_config 4. bind9_host_config All these configuration parameters are merged in a way where each successing config supercedes the previous one at a config-file level. To illustrate: @@ -59,7 +59,7 @@ bind9_group_config: - name: "." type: mirror -bind9_site_config: +bind9_leaf_config: - name: named.conf.local zone: - name: "." @@ -81,7 +81,7 @@ bind9_config: file: /etc/share/dns/root.hints ``` -The `named.conf.options` block in `bind9_default_config` got completely overwritten by the `bind9_group_config`, and the `bind9_site_config` completely overwrote `named.conf.local`, however, `named.conf.options` was left intact after merging with `bind9_site_config`. +The `named.conf.options` block in `bind9_default_config` got completely overwritten by the `bind9_group_config`, and the `bind9_leaf_config` completely overwrote `named.conf.local`, however, `named.conf.options` was left intact after merging with `bind9_leaf_config`. Configuration Grammar --------------------- diff --git a/defaults/main.yml b/defaults/main.yml index 34ba28d..42c96d6 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -14,7 +14,7 @@ bind9_debug_config: false bind9_config_indent: 4 bind9_group_config: [] -bind9_site_config: [] +bind9_leaf_config: [] bind9_host_config: [] bind9_default_config: @@ -30,7 +30,7 @@ bind9_default_config: bind9_config: "{{ [bind9_default_config, bind9_group_config, - bind9_site_config, + bind9_leaf_config, bind9_host_config] | community.general.lists_mergeby('name', recursive=true, diff --git a/meta/argument_specs.yml b/meta/argument_specs.yml deleted file mode 100644 index fac379f..0000000 --- a/meta/argument_specs.yml +++ /dev/null @@ -1,55 +0,0 @@ ---- -argument_specs: - main: - short_description: The main entry point for the bind9 role. - options: - bind9_config: - type: list - elements: dict - description: - - A list of configuration dictionaries that are merged to produce the final configuration. - - Each element must have a 'name' key (filename). - bind9_default_config: - type: list - elements: dict - description: Default configuration. - bind9_group_config: - type: list - elements: dict - description: Group-level configuration. - bind9_site_config: - type: list - elements: dict - description: Site/Leaf-level configuration. - bind9_host_config: - type: list - elements: dict - description: Host-level configuration. - bind9_backup_config: - type: bool - default: true - description: Whether to backup configuration files before overwriting. - bind9_debug_config: - type: bool - default: false - description: Whether to print the merged configuration during execution. - bind9_config_indent: - type: int - default: 4 - description: Indentation level for generated configuration files. - bind9_packages: - type: list - elements: str - description: List of packages to install. - bind9_cfgdir: - type: str - description: Directory for configuration files. - bind9_working_directory: - type: str - description: Working directory for BIND. - bind9_libdir: - type: str - description: Library directory for BIND. - bind9_backup_dir: - type: str - description: Directory for backups. diff --git a/tasks/main.yml b/tasks/main.yml index 12df4a5..d9585f0 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -16,69 +16,20 @@ owner: root group: root mode: 0750 - when: bind9_backup_config is defined and bind9_backup_config | bool + when: bind9_backup_config is defined and bind9_backup_config -- name: Deploy and Validate Configuration - block: - - name: Create backup of current config - ansible.builtin.copy: - src: "{{ bind9_cfgdir }}/{{ item.name }}" - dest: "{{ bind9_cfgdir }}/{{ item.name }}.bak" - remote_src: true - owner: root - group: bind - mode: 0640 - failed_when: false # It's okay if the file doesn't exist yet - # We do this for every file in the loop - loop: "{{ bind9_config }}" - loop_control: - label: "{{ item.name }}" - - - name: Template named.conf.generator - ansible.builtin.template: - src: named.conf.generator.j2 - dest: "{{ bind9_cfgdir }}/{{ item.name }}" - owner: root - group: bind - mode: 0640 - loop: "{{ bind9_config }}" - loop_control: - label: "{{ item.name }}" - register: _template_result - - - name: Validate configuration using named-checkconf - ansible.builtin.command: - cmd: "named-checkconf -z {{ bind9_cfgdir }}/named.conf" - changed_when: false - - rescue: - - name: Restore configuration from backup - ansible.builtin.copy: - src: "{{ bind9_cfgdir }}/{{ item.name }}.bak" - dest: "{{ bind9_cfgdir }}/{{ item.name }}" - remote_src: true - owner: root - group: bind - mode: 0640 - loop: "{{ bind9_config }}" - loop_control: - label: "{{ item.name }}" - failed_when: false # Best effort restore - - - name: Fail due to invalid configuration - ansible.builtin.fail: - msg: "Configuration validation failed. Changes have been reverted. Check the logs for named-checkconf errors." - - always: - - name: Remove backup files - ansible.builtin.file: - path: "{{ bind9_cfgdir }}/{{ item.name }}.bak" - state: absent - loop: "{{ bind9_config }}" - loop_control: - label: "{{ item.name }}" - when: bind9_backup_config | bool is false # Keep if backup is forced, otherwise cleanup temporary atomic backup - +- name: Template named.conf.generator + ansible.builtin.template: + src: named.conf.generator.j2 + dest: "{{ bind9_cfgdir }}/{{ item.name }}" + owner: root + group: bind + mode: 0640 + backup: "{{ item.backup | default('false') | bool }}" + # validate: 'named-checkconf -z -j %s' + loop: "{{ bind9_config }}" + loop_control: + label: "{{ item.name }}" tags: - bind9 - template From c334b2d4e7cf156d5e64059bf97378b7e5fa2920 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Thu, 22 Jan 2026 22:34:13 +0000 Subject: [PATCH 06/11] revert 25023891567ad8de141b481c5d4f613069f76c40 revert Merge pull request 'feature/bind9-20-support' (#1) from feature/bind9-20-support into main Reviewed-on: https://gitea/daniel/ansible-bind9-role/pulls/1 --- templates/named.conf.generator.j2 | 3 - templates/named.conf.options.j2 | 535 ++++++++++++++++++------- templates/named.conf.remote-servers.j2 | 20 - templates/named.conf.zone.j2 | 203 +++++++--- 4 files changed, 520 insertions(+), 241 deletions(-) delete mode 100644 templates/named.conf.remote-servers.j2 diff --git a/templates/named.conf.generator.j2 b/templates/named.conf.generator.j2 index 0199e32..ba4e518 100644 --- a/templates/named.conf.generator.j2 +++ b/templates/named.conf.generator.j2 @@ -54,6 +54,3 @@ {% if item.view is defined and item.view %} {% include 'named.conf.view.j2' %} {% endif %} -{% if item.remote_servers is defined and item.remote_servers %} -{% include 'named.conf.remote-servers.j2' %} -{% endif %} diff --git a/templates/named.conf.options.j2 b/templates/named.conf.options.j2 index d5fd43d..afdbaf7 100644 --- a/templates/named.conf.options.j2 +++ b/templates/named.conf.options.j2 @@ -1,28 +1,22 @@ -{% import 'named.conf.functions.j2' as functions with context %} options { {% filter indent(bind9_config_indent,true)%} -{# Iterate over keys to preserve user order (Python 3.7+ / Ansible dicts are ordered) #} -{% for key, value in item.options.items() %} -{% set conf_key = key | replace('_', '-') %} - -{# --- COMPLEX BLOCKS --- #} - -{% if key == 'rrset_order' %} +{# Unicorn Options#} +{% if item.options.rrset_order is defined and item.options.rrset_order %} rrset-order { {% filter indent(bind9_config_indent, true) %} -{% for rrset in value %} +{% for rrset in item.options.rrset_order %} {{ ('class ' + rrset.class | string + ' ') if rrset.class is defined and rrset.class -}} {{ ('type ' + rrset.type | string + ' ') if rrset.type is defined and rrset.type -}} {{ ('name "' + rrset.name | string + '" ') if rrset.name is defined and rrset.name -}} {{ ('order ' + rrset.order | string) -}}; {% endfor %} {% endfilter %}}; - -{% elif key == 'response_policy' %} +{% endif %} +{% if item.options.response_policy is defined and item.options.response_policy %} response-policy { {% filter indent(bind9_config_indent, true) %} -{% for zone in value.zones %} +{% for zone in item.options.response_policy.zones %} {{- ('zone ' + zone.zone | string) -}} {{- (' max-policy-ttl ' + zone.max_policy_ttl | string) if zone.max_policy_ttl is defined and zone.max_policy_ttl -}} {{- (' min-update-interval ' + zone.min_update_interval | string) if zone.min_update_interval is defined and zone.min_update_interval -}} @@ -34,86 +28,108 @@ response-policy { {{- (' nsdname-enable ' + functions.named_boolean(zone.nsdname_enable)) if zone.nsdname_enable is defined }}; {% endfor %} {% endfilter %}} -{{- (' max-policy-ttl ' + value.max_policy_ttl | string) if value.max_policy_ttl is defined and value.max_policy_ttl -}} -{{- (' min-update-interval ' + value.min_update_interval | string) if value.min_update_interval is defined and value.min_update_interval -}} -{{- (' min-ns-dots ' + value.min_ns_dots | string) if value.min_ns_dots is defined and value.min_ns_dots -}} -{{- (' add-soa ' + functions.named_boolean(value.add_soa)) if value.add_soa is defined -}} -{{- (' break-dnssec ' + functions.named_boolean(value.break_dnssec)) if value.break_dnssec is defined -}} -{{- (' nsip-wait-recurse ' + functions.named_boolean(value.nsip_wait_recurse)) if value.nsip_wait_recurse is defined -}} -{{- (' nsdname-wait-recurse ' + functions.named_boolean(value.nsdname_wait_recurse)) if value.nsdname_wait_recurse is defined -}} -{{- (' qname-wait-recurse ' + functions.named_boolean(value.qname_wait_recurse)) if value.qname_wait_recurse is defined -}} -{{- (' recursive-only ' + functions.named_boolean(value.recursive_only)) if value.recursive_only is defined -}} -{{- (' nsip-enable ' + functions.named_boolean(value.nsip_enable)) if value.nsip_enable is defined -}} -{{- (' nsdname-enable ' + functions.named_boolean(value.nsdname_enable)) if value.nsdname_enable is defined -}} -{{- (' dnsrps-enable ' + functions.named_boolean(value.dnsrps_enable)) if value.dnsrps_enable is defined -}} -{{- (' dnsrps-options { ' + value.dnsrps_options | join('; ') + '; }') if value.dnsrps_options is defined and value.dnsrps_options -}}; - -{% elif key == 'response_padding' %} +{{- (' max-policy-ttl ' + item.options.response_policy.max_policy_ttl | string) if item.options.response_policy.max_policy_ttl is defined and item.options.response_policy.max_policy_ttl -}} +{{- (' min-update-interval ' + item.options.response_policy.min_update_interval | string) if item.options.response_policy.min_update_interval is defined and item.options.response_policy.min_update_interval -}} +{{- (' min-ns-dots ' + item.options.response_policy.min_ns_dots | string) if item.options.response_policy.min_ns_dots is defined and item.options.response_policy.min_ns_dots -}} +{{- (' add-soa ' + functions.named_boolean(item.options.response_policy.add_soa)) if item.options.response_policy.add_soa is defined -}} +{{- (' break-dnssec ' + functions.named_boolean(item.options.response_policy.break_dnssec)) if item.options.response_policy.break_dnssec is defined -}} +{{- (' nsip-wait-recurse ' + functions.named_boolean(item.options.response_policy.nsip_wait_recurse)) if item.options.response_policy.nsip_wait_recurse is defined -}} +{{- (' nsdname-wait-recurse ' + functions.named_boolean(item.options.response_policy.nsdname_wait_recurse)) if item.options.response_policy.nsdname_wait_recurse is defined -}} +{{- (' qname-wait-recurse ' + functions.named_boolean(item.options.response_policy.qname_wait_recurse)) if item.options.response_policy.qname_wait_recurse is defined -}} +{{- (' recursive-only ' + functions.named_boolean(item.options.response_policy.recursive_only)) if item.options.response_policy.recursive_only is defined -}} +{{- (' nsip-enable ' + functions.named_boolean(item.options.response_policy.nsip_enable)) if item.options.response_policy.nsip_enable is defined -}} +{{- (' nsdname-enable ' + functions.named_boolean(item.options.response_policy.nsdname_enable)) if item.options.response_policy.nsdname_enable is defined -}} +{{- (' dnsrps-enable ' + functions.named_boolean(item.options.response_policy.dnsrps_enable)) if item.options.response_policy.dnsrps_enable is defined -}} +{{- (' dnsrps-options { ' + item.options.response_policy.dnsrps_options | join('; ') + '; }') if item.options.response_policy.dnsrps_options is defined and item.options.response_policy.dnsrps_options -}}; +{% endif %} +{% if item.options.response_padding is defined and item.options.response_padding %} response-padding { -{{ functions.simple_item_list(value.addresses) }}} -{{- (' block-size ' + value.block_size | string) }}; - -{% elif key == 'rate_limit' %} +{{ functions.simple_item_list(item.options.response_padding.addresses) }}} +{{- (' block-size ' + item.options.response_padding.block_size | string) }}; +{% endif %} +{% if item.options.rate_limit is defined and item.options.rate_limit %} rate-limit { {% filter indent(bind9_config_indent, true) %} -{{ ('all-per-second ' + value.all_per_second | string + ';\n') if value.all_per_second is defined and value.all_per_second -}} -{{ ('errors-per-second ' + value.errors_per_second | string + ';\n') if value.errors_per_second is defined and value.errors_per_second -}} -{{ ('responses-per-second ' + value.responses_per_second | string + ';\n') if value.responses_per_second is defined and value.responses_per_second -}} -{{ ('referrals-per-second ' + value.referrals_per_second | string + ';\n') if value.referrals_per_second is defined and value.referrals_per_second -}} -{{ ('nodata-per-second ' + value.nodata_per_second | string + ';\n') if value.nodata_per_second is defined and value.nodata_per_second -}} -{{ ('nxdomains-per-second ' + value.nxdomains_per_second | string + ';\n') if value.nxdomains_per_second is defined and value.nxdomains_per_second -}} -{{ ('ipv4-prefix-length ' + value.ipv4_prefix_length | string + ';\n') if value.ipv4_prefix_length is defined and value.ipv4_prefix_length -}} -{{ ('ipv6-prefix-length ' + value.ipv6_prefix_length | string + ';\n') if value.ipv6_prefix_length is defined and value.ipv6_prefix_length -}} -{{ ('max-table-size ' + value.max_table_size | string + ';\n') if value.max_table_size is defined and value.max_table_size -}} -{{ ('min-table-size ' + value.min_table_size | string + ';\n') if value.min_table_size is defined and value.min_table_size -}} -{{ ('qps-scale ' + value.qps_scale | string + ';\n') if value.qps_scale is defined and value.qps_scale -}} -{{ ('window ' + value.window | string + ';\n') if value.window is defined and value.window -}} -{{ ('slip ' + value.slip | string + ';\n') if value.slip is defined and value.slip -}} -{{ ('log-only ' + functions.named_boolean(value.log_only) + ';\n') if value.log_only is defined -}} -{{ ('exempt-clients {\n' + functions.simple_item_list(value.exempt_clients) + '};\n') if value.exempt_clients is defined and value.exempt_clients -}} +{{ ('all-per-second ' + item.options.rate_limit.all_per_second | string + ';\n') if item.options.rate_limit.all_per_second is defined and item.options.rate_limit.all_per_second -}} +{{ ('errors-per-second ' + item.options.rate_limit.errors_per_second | string + ';\n') if item.options.rate_limit.errors_per_second is defined and item.options.rate_limit.errors_per_second -}} +{{ ('responses-per-second ' + item.options.rate_limit.responses_per_second | string + ';\n') if item.options.rate_limit.responses_per_second is defined and item.options.rate_limit.responses_per_second -}} +{{ ('referrals-per-second ' + item.options.rate_limit.referrals_per_second | string + ';\n') if item.options.rate_limit.referrals_per_second is defined and item.options.rate_limit.referrals_per_second -}} +{{ ('nodata-per-second ' + item.options.rate_limit.nodata_per_second | string + ';\n') if item.options.rate_limit.nodata_per_second is defined and item.options.rate_limit.nodata_per_second -}} +{{ ('nxdomains-per-second ' + item.options.rate_limit.nxdomains_per_second | string + ';\n') if item.options.rate_limit.nxdomains_per_second is defined and item.options.rate_limit.nxdomains_per_second -}} +{{ ('ipv4-prefix-length ' + item.options.rate_limit.ipv4_prefix_length | string + ';\n') if item.options.rate_limit.ipv4_prefix_length is defined and item.options.rate_limit.ipv4_prefix_length -}} +{{ ('ipv6-prefix-length ' + item.options.rate_limit.ipv6_prefix_length | string + ';\n') if item.options.rate_limit.ipv6_prefix_length is defined and item.options.rate_limit.ipv6_prefix_length -}} +{{ ('max-table-size ' + item.options.rate_limit.max_table_size | string + ';\n') if item.options.rate_limit.max_table_size is defined and item.options.rate_limit.max_table_size -}} +{{ ('min-table-size ' + item.options.rate_limit.min_table_size | string + ';\n') if item.options.rate_limit.min_table_size is defined and item.options.rate_limit.min_table_size -}} +{{ ('qps-scale ' + item.options.rate_limit.qps_scale | string + ';\n') if item.options.rate_limit.qps_scale is defined and item.options.rate_limit.qps_scale -}} +{{ ('window ' + item.options.rate_limit.window | string + ';\n') if item.options.rate_limit.window is defined and item.options.rate_limit.window -}} +{{ ('slip ' + item.options.rate_limit.slip | string + ';\n') if item.options.rate_limit.slip is defined and item.options.rate_limit.slip -}} +{{ ('log-only ' + functions.named_boolean(item.options.rate_limit.log_only) + ';\n') if item.options.rate_limit.log_only is defined -}} +{{ ('exempt-clients {\n' + functions.simple_item_list(item.options.rate_limit.exempt_clients) + '};\n') if item.options.rate_limit.exempt_clients is defined and item.options.rate_limit.exempt_clients -}} {% endfilter %}}; - -{% elif key == 'listen_on_v6' or key == 'listen_on' %} -{% for listen in (value if value is not mapping else [value]) %} -{{ conf_key }} +{% endif %} +{% if item.options.listen_on_v6 is defined and item.options.listen_on_v6 %} +{% for listen in item.options.listen_on_v6 if item.options.listen_on_v6 is not mapping %} +listen-on-v6 {{- (' port ' + listen.port | string) if listen.port is defined and listen.port -}} {{- (' dscp ' + listen.dscp | string) if listen.dscp is defined and listen.dscp -}} {{- (' tls ' + listen.tls | string) if listen.tls is defined and listen.tls -}} {{- (' http ' + listen.http | string) if listen.http is defined and listen.http }} { {{ functions.simple_item_list(listen.addresses) }}}; +{% else %} +listen-on-v6 +{{- (' port ' + item.options.listen_on_v6.port | string) if item.options.listen_on_v6.port is defined and item.options.listen_on_v6.port -}} +{{- (' dscp ' + item.options.listen_on_v6.dscp | string) if item.options.listen_on_v6.dscp is defined and item.options.listen_on_v6.dscp -}} +{{- (' tls ' + item.options.listen_on_v6.tls | string) if item.options.listen_on_v6.tls is defined and item.options.listen_on_v6.tls -}} +{{- (' http ' + item.options.listen_on_v6.http | string) if item.options.listen_on_v6.http is defined and item.options.listen_on_v6.http }} { +{{ functions.simple_item_list(item.options.listen_on_v6.addresses) }}}; {% endfor %} - -{% elif key == 'forwarders' %} -{{ functions.parent_address_port_dscp("forwarders", value) -}} - -{% elif key == 'dual_stack_servers' %} +{% endif %} +{% if item.options.listen_on is defined and item.options.listen_on %} +{% for listen in item.options.listen_on if item.options.listen_on is not mapping %} +listen-on +{{- (' port ' + listen.port | string) if listen.port is defined and listen.port -}} +{{- (' dscp ' + listen.dscp | string) if listen.dscp is defined and listen.dscp -}} +{{- (' tls ' + listen.tls | string) if listen.tls is defined and listen.tls -}} +{{- (' http ' + listen.http | string) if listen.http is defined and listen.http }} { +{{ functions.simple_item_list(listen.addresses) }}}; +{% else %} +listen-on +{{- (' port ' + item.options.listen_on.port | string) if item.options.listen_on.port is defined and item.options.listen_on.port -}} +{{- (' dscp ' + item.options.listen_on.dscp | string) if item.options.listen_on.dscp is defined and item.options.listen_on.dscp -}} +{{- (' tls ' + item.options.listen_on.tls | string) if item.options.listen_on.tls is defined and item.options.listen_on.tls -}} +{{- (' http ' + item.options.listen_on.http | string) if item.options.listen_on.http is defined and item.options.listen_on.http }} { +{{ functions.simple_item_list(item.options.listen_on.addresses) }}}; +{% endfor %} +{% endif %} +{{ functions.parent_address_port_dscp("forwarders", item.options.forwarders) if item.options.forwarders is defined and item.options.forwarders -}} +{% if item.options.dual_stack_servers is defined and item.options.dual_stack_servers %} dual-stack-servers -{{ (' port ' + value.port | string) if value.port is defined and value }} { -{% for host in value.addresses %} +{{ (' port ' + item.options.dual_stack_servers.port | string) if item.options.dual_stack_servers.port is defined and item.options.dual_stack_servers }} { +{% for host in item.options.dual_stack_servers.addresses %} {% filter indent(bind9_config_indent, true) %} {{ host.address | ansible.utils.ipaddr | ternary(host.address, '"' + host.address + '"') }} {{- (' port ' + host.port | string) if host.port is defined and host.port -}} {{- (' dscp ' + host.dscp | string) if host.dscp is defined and host.dscp -}}; {% endfilter %} {% endfor %}}; - -{% elif key == 'dnstap_output' %} -dnstap-output {{ value.output_type -}} -{{- ' "' + value.output_file + '"' -}} -{{- (' size ' + value.size | string) if value.size is defined and value.size -}} -{{- (' versions ' + value.versions | string) if value.versions is defined and value.versions -}} -{{- (' suffix ' + value.suffix | string) if value.suffix is defined and value.suffix -}}; - -{% elif key == 'dnstap' %} +{% endif %} +{% if item.options.dnstap_output is defined and item.options.dnstap_output %} +dnstap-output {{ item.options.dnstap_output.output_type -}} +{{- ' "' + item.options.dnstap_output.output_file + '"' -}} +{{- (' size ' + item.options.dnstap_output.size | string) if item.options.dnstap_output.size is defined and item.options.dnstap_output.size -}} +{{- (' versions ' + item.options.dnstap_output.versions | string) if item.options.dnstap_output.versions is defined and item.options.dnstap_output.versions -}} +{{- (' suffix ' + item.options.dnstap_output.suffix | string) if item.options.dnstap_output.suffix is defined and item.options.dnstap_output.suffix -}}; +{% endif %} +{% if item.options.dnstap is defined and item.options.dnstap %} dnstap { {% filter indent(bind9_config_indent, true) %} -{% for dnstap in value %} +{% for dnstap in item.options.dnstap %} {{ dnstap.type }}{{ ' ' + dnstap.log if dnstap.log is defined and dnstap.log }}; {% endfor %} {% endfilter %}}; - -{% elif key == 'dns64' %} -{% for dns64 in (value if value is sequence else [value]) %} +{% endif %} +{% if item.options.dns64 is defined and item.options.dns64 %} +{% for dns64 in item.options.dns64 if item.options.dns64 is sequence %} dns64 {{ dns64.netprefix }} { {% filter indent(bind9_config_indent, true) %} {{ ('break-dnssec ' + functions.named_boolean(dns64.break_dnssec) + ';\n') if dns64.break_dnssec is defined and dns64.break_dnssec is boolean -}} @@ -124,31 +140,31 @@ dns64 {{ dns64.netprefix }} { {{ ("mapped {\n" + functions.simple_item_list(dns64.mapped) + "};\n") if dns64.mapped is defined and dns64.mapped -}} {% endfilter %}}; {% endfor %} - -{% elif key == 'deny_answer_aliases' %} +{% endif %} +{% if item.options.deny_answer_aliases is defined and item.options.deny_answer_aliases %} deny-answer-aliases { -{{ functions.simple_item_list(value.names) }}} -{%- if value.except_from is defined and value.except_from %} +{{ functions.simple_item_list(item.options.deny_answer_aliases.names) }}} +{%- if item.options.deny_answer_aliases.except_from is defined and item.options.deny_answer_aliases.except_from %} except-from { -{{ functions.simple_item_list(value.except_from, 4) }}} +{{ functions.simple_item_list(item.options.deny_answer_aliases.except_from, 4) }}} {%- endif %}; - -{% elif key == 'deny_answer_addresses' %} +{% endif %} +{% if item.options.deny_answer_addresses is defined and item.options.deny_answer_addresses %} deny-answer-addresses { -{{ functions.simple_item_list(value.addresses) }}} -{%- if value.except_from is defined and value.except_from %} +{{ functions.simple_item_list(item.options.deny_answer_addresses.addresses) }}} +{%- if item.options.deny_answer_addresses.except_from is defined and item.options.deny_answer_addresses.except_from %} except-from { -{{ functions.simple_item_list(value.except_from, 4) }}} +{{ functions.simple_item_list(item.options.deny_answer_addresses.except_from, 4) }}} {%- endif %}; - -{% elif key == 'check_names' %} -{% for policy in value %} +{% endif %} +{% if item.options.check_names is defined and item.options.check_names %} +{% for policy in item.options.check_names %} check-names {{ policy.type }} {{ policy.action }}; {% endfor %} - -{% elif key == 'catalog_zones' %} +{% endif %} +{% if item.options.catalog_zones is defined and item.options.catalog_zones %} catalog-zones { -{% for catalog_zone in value %} +{% for catalog_zone in item.options.catalog_zones %} zone {{ catalog_zone.zone }} {% filter indent(bind9_config_indent, true) %} {% if catalog_zone.default_primaries is defined and catalog_zone.default_primaries %} @@ -162,80 +178,291 @@ default-primaries {{ ('min-update-interval ' + catalog_zone.min_update_interval | string) if catalog_zone.min_update_interval is defined and catalog_zone.min_update_interval}}; {% endfilter %} {% endfor %}}; - -{% elif key in ['transfer_source', 'transfer_source_v6', 'alt_transfer_source', 'alt_transfer_source_v6', 'query_source', 'query_source_v6', 'parental_source', 'parental_source_v6', 'notify_source', 'notify_source_v6'] %} -{{ functions.single_ip_port_dscp(conf_key, value) -}} - -{% elif key == 'also_notify' and value is not string %} +{% endif %} +{{ functions.single_ip_port_dscp('transfer-source', item.options.transfer_source) if item.options.transfer_source is defined and item.options.transfer_source -}} +{{ functions.single_ip_port_dscp('transfer-source-v6', item.options.transfer_source_v6) if item.options.transfer_source_v6 is defined and item.options.transfer_source_v6 -}} +{{ functions.single_ip_port_dscp('alt-transfer-source', item.options.alt_transfer_source) if item.options.alt_transfer_source is defined and item.options.alt_transfer_source -}} +{{ functions.single_ip_port_dscp('alt-transfer-source-v6', item.options.alt_transfer_source_v6) if item.options.alt_transfer_source_v6 is defined and item.options.alt_transfer_source_v6 -}} +{{ functions.single_ip_port_dscp('query-source', item.options.query_source) if item.options.query_source is defined and item.options.query_source -}} +{{ functions.single_ip_port_dscp('query-source-v6', item.options.query_source_v6) if item.options.query_source_v6 is defined and item.options.query_source_v6 -}} +{{ functions.single_ip_port_dscp('parental-source', item.options.parental_source) if item.options.parental_source is defined and item.options.parental_source -}} +{{ functions.single_ip_port_dscp('parental-source-v6', item.options.parental_source_v6) if item.options.parental_source_v6 is defined and item.options.parental_source_v6 -}} +{{ functions.single_ip_port_dscp('notify-source', item.options.notify_source) if item.options.notify_source is defined and item.options.notify_source -}} +{{ functions.single_ip_port_dscp('notify-source-v6', item.options.notify_source_v6) if item.options.notify_source_v6 is defined and item.options.notify_source_v6 -}} +{% if item.options.also_notify is defined and item.options.also_notify is not string %} also-notify -{{- (' port ' + value.port | string) if value.port is defined and value.port -}} -{{- (' dscp ' + value.dscp | string) if value.dscp is defined and value.dscp }} { -{{ functions.list_address_port_key_tls(value.addresses) }}}; - -{% elif key == 'allow_transfer' and value is not string %} +{{- (' port ' + item.options.also_notify.port | string) if item.options.also_notify.port is defined and item.options.also_notify.port -}} +{{- (' dscp ' + item.options.also_notify.dscp | string) if item.options.also_notify.dscp is defined and item.options.also_notify.dscp }} { +{{ functions.list_address_port_key_tls(item.options.also_notify.addresses) }}}; +{% endif %} +{% if item.options.allow_transfer is defined and item.options.allow_transfer is not string %} allow-transfer -{{- (' port ' + value.port | string) if value.port is defined and value.port -}} -{{- (' transport ' + value.transport) if value.transport is defined and value.transport }} { -{{ functions.simple_item_list(value.addresses) }}}; - -{% elif key == 'disable_algorithms' %} -{% for item in value %} +{{- (' port ' + item.options.allow_transfer.port | string) if item.options.allow_transfer.port is defined and item.options.allow_transfer.port -}} +{{- (' transport ' + item.options.allow_transfer.transport) if item.options.allow_transfer.transport is defined and item.options.allow_transfer.transport }} { +{{ functions.simple_item_list(item.options.allow_transfer.addresses) }}}; +{% endif %} +{# The rest #} +{% if item.options.disable_algorithms is defined and item.options.disable_algorithms %} +{% for item in item.options.disable_algorithms %} disable-algorithms {{ item.domain }} { "{{ item.algorithms | join('"; "') }}"; }; {% endfor %} - -{% elif key == 'disable_ds_digests' %} -{% for item in value %} +{% endif %} +{% if item.options.disable_ds_digests is defined and item.options.disable_ds_digests %} +{% for item in item.options.disable_ds_digests %} disable-ds-digests {{ item.domain }} { "{{ item.digests | join('"; "') }}"; }; {% endfor %} - -{% elif key == 'root_delegation_only' %} -root-delegation-only{% if value.exclude is defined and value.exclude is sequence %} exclude { -{{ functions.simple_item_list(value.exclude) }}} -{% endif %}; - -{% elif key == 'tkey_dhkey' %} -tkey-dhkey "{{ value.key_name }}" {{ value.key_tag }}; - -{# --- SPECIAL QUOTED STRINGS --- #} -{% elif key in ['dnstap_identity', 'server_id'] %} -{{ functions.reserved_or_quoted(conf_key, value, ['none', 'hostname']) -}} - -{% elif key in ['dnstap_version', 'geoip_directory', 'hostname', 'lock_file', 'pid_file', 'random_device', 'session_keyfile', 'version'] %} -{{ functions.reserved_or_quoted(conf_key, value, ['none']) -}} - -{# --- DEPRECATED/OBSOLETE --- #} -{% elif key == 'tkey_domain' %} -{# Obsolete in 9.20 #} -/* WARN: tkey-domain is obsolete in BIND 9.20 */ -{{ functions.reserved_or_quoted(conf_key, value, ['none']) -}} - -{% elif key == 'tkey_gssapi_credential' %} -{# Deprecated in 9.20 #} -/* WARN: tkey-gssapi-credential is deprecated in BIND 9.20; use tkey-gssapi-keytab */ -{{ functions.reserved_or_quoted(conf_key, value, ['none']) -}} - -{# --- SIMPLE LISTS --- #} -{% elif key in ['allow_notify', 'allow_query', 'allow_query_cache', 'allow_query_cache_on', 'allow_query_on', 'allow_recursion', 'allow_recursion_on', 'allow_update', 'allow_update_forwarding', 'blackhole', 'keep_response_order', 'no_case_compress', 'sortlist', 'avoid_v4_udp_ports', 'avoid_v6_udp_ports', 'use_v4_udp_ports', 'use_v6_udp_ports', 'validate_except'] %} -{{ conf_key }} { -{{ functions.simple_item_list(value) }}}; - -{# --- QUOTED STRINGS --- #} -{% elif key in ['bindkeys_file', 'directory', 'dump_file', 'key_directory', 'managed_keys_directory', 'memstatistics_file', 'new_zones_directory', 'recursing_file', 'secroots_file', 'statistics_file', 'tkey_gssapi_keytab'] %} -{{ conf_key }} "{{ value }}"; - -{# --- BOOLEANS --- #} -{% elif key in ['allow_new_zones', 'answer_cookie', 'auth_nxdomain', 'automatic_interface_scan', 'check_integrity', 'check_sibling', 'check_wildcard', 'dnsrps_enable', 'dnssec_accept_expired', 'dnssec_dnskey_kskonly', 'dnssec_secure_to_insecure', 'empty_zones_enable', 'flush_zones_on_shutdown', 'glue_cache', 'ipv4only_enable', 'match_mapped_addresses', 'memstatistics', 'message_compression', 'minimal_any', 'multi_master', 'notify_to_soa', 'provide_ixfr', 'querylog', 'recursion', 'request_expire', 'request_ixfr', 'request_nsid', 'require_server_cookie', 'reuseport', 'root_key_sentinel', 'send_cookie', 'stale_answer_enable', 'stale_cache_enable', 'synth_from_dnssec', 'trust_anchor_telemetry', 'try_tcp_refresh', 'update_check_ksk', 'use_alt_transfer_source', 'zero_no_soa_ttl', 'zero_no_soa_ttl_cache'] %} -{{ functions.boolean_option(conf_key, value) }} - -{# --- BOOLEAN OR STRING --- #} -{% elif key in ['dialup', 'ixfr_from_differences', 'minimal_responses', 'notify', 'zone_statistics', 'dnssec_validation'] %} -{{ conf_key }} {{ functions.boolean_or_string(value) }}; - -{# --- FALLTHROUGH --- #} -{% else %} -{# Strict mode: Ignore unknown keys or warn if possible. For now, silence is safer than invalid config. #} {% endif %} - -{% endfor %} +{# Oddball simple options #} +{% if item.options.fetch_quota_params is defined and item.options.fetch_quota_params is string %} +fetch-quota-params {{ item.options.fetch_quota_params }}; +{% endif %} +{% if item.options.fetches_per_server is defined and item.options.fetches_per_server is string %} +fetches-per-server {{ item.options.fetches_per_server }}; +{% endif %} +{% if item.options.fetches_per_zone is defined and item.options.fetches_per_zone is string %} +fetches-per-zone {{ item.options.fetches_per_zone }}; +{% endif %} +{% if item.options.prefetch is defined and item.options.prefetch %} +prefetch {{ item.options.prefetch }}; +{% endif %} +{% if item.options.root_delegation_only is defined and item.options.root_delegation_only %} +root-delegation-only{% if item.options.root_delegation_only.exclude is defined and item.options.root_delegation_only.exclude is sequence %} exclude { +{{ functions.simple_item_list(item.options.root_delegation_only.exclude) }}} +{% endif %}; +{% endif %} +{% if item.options.sig_validity_interval is defined and item.options.sig_validity_interval %} +sig-validity-interval {{ item.options.sig_validity_interval }}; +{% endif %} +{% if item.options.tkey_dhkey is defined and item.options.tkey_dhkey is mapping %} +tkey-dhkey "{{ item.options.tkey_dhkey.key_name }}" {{ item.options.tkey_dhkey.key_tag }}; +{% endif %} +{# special_quoted_string options with reserved keywords #} +{% if item.options.dnstap_identity is defined and item.options.dnstap_identity is string %} +{{ functions.reserved_or_quoted('dnstap-identity', item.options.dnstap_identity, ['none', 'hostname']) -}} +{% endif %} +{% if item.options.dnstap_version is defined and item.options.dnstap_version is string %} +{{ functions.reserved_or_quoted('dnstap-version', item.options.dnstap_version, ['none']) -}} +{% endif %} +{% if item.options.geoip_directory is defined and item.options.geoip_directory is string %} +{{ functions.reserved_or_quoted('geoip-directory', item.options.geoip_directory, ['none']) -}} +{% endif %} +{% if item.options.hostname is defined and item.options.hostname is string %} +{{ functions.reserved_or_quoted('hostname', item.options.hostname, ['none']) -}} +{% endif %} +{% if item.options.lock_file is defined and item.options.lock_file is string %} +{{ functions.reserved_or_quoted('lock-file', item.options.lock_file, ['none']) -}} +{% endif %} +{% if item.options.pid_file is defined and item.options.pid_file is string %} +{{ functions.reserved_or_quoted('pid-file', item.options.pid_file, ['none']) -}} +{% endif %} +{% if item.options.random_device is defined and item.options.random_device is string %} +{{ functions.reserved_or_quoted('random-device', item.options.random_device, ['none']) -}} +{% endif %} +{% if item.options.server_id is defined and item.options.server_id is string %} +{{ functions.reserved_or_quoted('server-id', item.options.server_id, ['none', 'hostname']) -}} +{% endif %} +{% if item.options.session_keyfile is defined and item.options.session_keyfile is string %} +{{ functions.reserved_or_quoted('session-keyfile', item.options.session_keyfile, ['none']) -}} +{% endif %} +{% if item.options.version is defined and item.options.version is string %} +{{ functions.reserved_or_quoted('version', item.options.version, ['none']) -}} +{% endif %} +{# simple list options #} +{{ ('avoid-v4-udp-ports {\n' + functions.simple_item_list(item.options.avoid_v4_udp_ports) + '};\n') if item.options.avoid_v4_udp_ports is defined and item.options.avoid_v4_udp_ports -}} +{{ ('avoid-v6-udp-ports {\n' + functions.simple_item_list(item.options.avoid_v6_udp_ports) + '};\n') if item.options.avoid_v6_udp_ports is defined and item.options.avoid_v6_udp_ports -}} +{{ ('use-v4-udp-ports {\n' + functions.simple_item_list(item.options.use_v4_udp_ports) + '};\n') if item.options.use_v4_udp_ports is defined and item.options.use_v4_udp_ports -}} +{{ ('use-v6-udp-ports {\n' + functions.simple_item_list(item.options.use_v6_udp_ports) + '};\n') if item.options.use_v6_udp_ports is defined and item.options.use_v6_udp_ports -}} +{{ ('validate-except {\n' + functions.simple_item_list(item.options.validate_except) + '};\n') if item.options.validate_except is defined and item.options.validate_except -}} +{# boolean_or_string options #} +{{ ('dialup ' + functions.boolean_or_string(item.options.dialup) + ';\n') if item.options.dialup is defined -}} +{{ ('ixfr-from-differences ' + functions.boolean_or_string(item.options.ixfr_from_differences) + ';\n') if item.options.ixfr_from_differences is defined -}} +{{ ('minimal-responses ' + functions.boolean_or_string(item.options.minimal_responses) + ';\n') if item.options.minimal_responses is defined -}} +{{ ('notify ' + functions.boolean_or_string(item.options.notify) + ';\n') if item.options.notify is defined -}} +{{ ('zone-statistics ' + functions.boolean_or_string(item.options.zone_statistics) + ';\n') if item.options.zone_statistics is defined -}} +{# duration_sizeval options #} +{{ ('fstrm-set-reopen-interval ' + item.options.fstrm_set_reopen_interval | string +';\n') if item.options.fstrm_set_reopen_interval is defined and item.options.fstrm_set_reopen_interval -}} +{{ ('interface-interval ' + item.options.interface_interval | string +';\n') if item.options.interface_interval is defined and item.options.interface_interval -}} +{{ ('lame-ttl ' + item.options.lame_ttl | string +';\n') if item.options.lame_ttl is defined and item.options.lame_ttl -}} +{{ ('lmdb-mapsize ' + item.options.lmdb_mapsize | string +';\n') if item.options.lmdb_mapsize is defined and item.options.lmdb_mapsize -}} +{{ ('max-cache-ttl ' + item.options.max_cache_ttl | string +';\n') if item.options.max_cache_ttl is defined and item.options.max_cache_ttl -}} +{{ ('max-ncache-ttl ' + item.options.max_ncache_ttl | string +';\n') if item.options.max_ncache_ttl is defined and item.options.max_ncache_ttl -}} +{{ ('max-stale-ttl ' + item.options.max_stale_ttl | string +';\n') if item.options.max_stale_ttl is defined and item.options.max_stale_ttl -}} +{{ ('min-cache-ttl ' + item.options.min_cache_ttl | string +';\n') if item.options.min_cache_ttl is defined and item.options.min_cache_ttl -}} +{{ ('min-ncache-ttl ' + item.options.min_ncache_ttl | string +';\n') if item.options.min_ncache_ttl is defined and item.options.min_ncache_ttl -}} +{{ ('nta-lifetime ' + item.options.nta_lifetime | string +';\n') if item.options.nta_lifetime is defined and item.options.nta_lifetime -}} +{{ ('nta-recheck ' + item.options.nta_recheck | string +';\n') if item.options.nta_recheck is defined and item.options.nta_recheck -}} +{{ ('servfail-ttl ' + item.options.servfail_ttl | string +';\n') if item.options.servfail_ttl is defined and item.options.servfail_ttl -}} +{{ ('stale-answer-ttl ' + item.options.stale_answer_ttl | string +';\n') if item.options.stale_answer_ttl is defined and item.options.stale_answer_ttl -}} +{{ ('stale-refresh-time ' + item.options.stale_refresh_time | string +';\n') if item.options.stale_refresh_time is defined and item.options.stale_refresh_time -}} +{# special options options #} +{{ ('auto-dnssec ' + item.options.auto_dnssec | string +';\n') if item.options.auto_dnssec is defined and item.options.auto_dnssec -}} +{{ ('check-dup-records ' + item.options.check_dup_records | string +';\n') if item.options.check_dup_records is defined and item.options.check_dup_records -}} +{{ ('check-mx ' + item.options.check_mx | string +';\n') if item.options.check_mx is defined and item.options.check_mx -}} +{{ ('check-mx-cname ' + item.options.check_mx_cname | string +';\n') if item.options.check_mx_cname is defined and item.options.check_mx_cname -}} +{{ ('check-spf ' + item.options.check_spf | string +';\n') if item.options.check_spf is defined and item.options.check_spf -}} +{{ ('check-srv-cname ' + item.options.check_srv_cname | string +';\n') if item.options.check_srv_cname is defined and item.options.check_srv_cname -}} +{{ ('cookie-algorithm ' + item.options.cookie_algorithm | string +';\n') if item.options.cookie_algorithm is defined and item.options.cookie_algorithm -}} +{{ ('coresize ' + item.options.coresize | string +';\n') if item.options.coresize is defined and item.options.coresize -}} +{{ ('datasize ' + item.options.datasize | string +';\n') if item.options.datasize is defined and item.options.datasize -}} +{{ ('dnssec-update-mode ' + item.options.dnssec_update_mode | string +';\n') if item.options.dnssec_update_mode is defined and item.options.dnssec_update_mode -}} +{{ ('dnssec-validation ' + functions.boolean_or_string(item.options.dnssec_validation) +';\n') if item.options.dnssec_validation is defined -}} +{{ ('files ' + item.options.files | string +';\n') if item.options.files is defined and item.options.files -}} +{{ ('forward ' + item.options.forward | string +';\n') if item.options.forward is defined and item.options.forward -}} +{{ ('fstrm-set-output-queue-model ' + item.options.fstrm_set_output_queue_model | string +';\n') if item.options.fstrm_set_output_queue_model is defined and item.options.fstrm_set_output_queue_model -}} +{{ ('masterfile-format ' + item.options.masterfile_format | string +';\n') if item.options.masterfile_format is defined and item.options.masterfile_format -}} +{{ ('masterfile-style ' + item.options.masterfile_style | string +';\n') if item.options.masterfile_style is defined and item.options.masterfile_style -}} +{{ ('max-cache-size ' + item.options.max_cache_size | string +';\n') if item.options.max_cache_size is defined and item.options.max_cache_size -}} +{{ ('max-ixfr-ratio ' + item.options.max_ixfr_ratio | string +';\n') if item.options.max_ixfr_ratio is defined and item.options.max_ixfr_ratio -}} +{{ ('max-journal-size ' + item.options.max_journal_size | string +';\n') if item.options.max_journal_size is defined and item.options.max_journal_size -}} +{{ ('max-zone-ttl ' + item.options.max_zone_ttl | string +';\n') if item.options.max_zone_ttl is defined and item.options.max_zone_ttl -}} +{{ ('qname-minimization ' + item.options.qname_minimization | string +';\n') if item.options.qname_minimization is defined and item.options.qname_minimization -}} +{{ ('serial-update-method ' + item.options.serial_update_method | string +';\n') if item.options.serial_update_method is defined and item.options.serial_update_method -}} +{{ ('stacksize ' + item.options.stacksize | string +';\n') if item.options.stacksize is defined and item.options.stacksize -}} +{{ ('stale-answer-client-timeout ' + item.options.stale_answer_client_timeout | string +';\n') if item.options.stale_answer_client_timeout is defined and item.options.stale_answer_client_timeout -}} +{{ ('transfer-format ' + item.options.transfer_format | string +';\n') if item.options.transfer_format is defined and item.options.transfer_format -}} +{# quoted_string options #} +{{ ('bindkeys-file "' + item.options.bindkeys_file | string +'";\n') if item.options.bindkeys_file is defined and item.options.bindkeys_file -}} +{{ ('directory "' + item.options.directory | string +'";\n') if item.options.directory is defined and item.options.directory -}} +{{ ('dump-file "' + item.options.dump_file | string +'";\n') if item.options.dump_file is defined and item.options.dump_file -}} +{{ ('key-directory "' + item.options.key_directory | string +'";\n') if item.options.key_directory is defined and item.options.key_directory -}} +{{ ('managed-keys-directory "' + item.options.managed_keys_directory | string +'";\n') if item.options.managed_keys_directory is defined and item.options.managed_keys_directory -}} +{{ ('memstatistics-file "' + item.options.memstatistics_file | string +'";\n') if item.options.memstatistics_file is defined and item.options.memstatistics_file -}} +{{ ('new-zones-directory "' + item.options.new_zones_directory | string +'";\n') if item.options.new_zones_directory is defined and item.options.new_zones_directory -}} +{{ ('recursing-file "' + item.options.recursing_file | string +'";\n') if item.options.recursing_file is defined and item.options.recursing_file -}} +{{ ('secroots-file "' + item.options.secroots_file | string +'";\n') if item.options.secroots_file is defined and item.options.secroots_file -}} +{{ ('statistics-file "' + item.options.statistics_file | string +'";\n') if item.options.statistics_file is defined and item.options.statistics_file -}} +{{ ('tkey-domain "' + item.options.tkey_domain | string +'";\n') if item.options.tkey_domain is defined and item.options.tkey_domain -}} +{{ ('tkey-gssapi-credential "' + item.options.tkey_gssapi_credential | string +'";\n') if item.options.tkey_gssapi_credential is defined and item.options.tkey_gssapi_credential -}} +{{ ('tkey-gssapi-keytab "' + item.options.tkey_gssapi_keytab | string +'";\n') if item.options.tkey_gssapi_keytab is defined and item.options.tkey_gssapi_keytab -}} +{# simple_item_list options #} +{{ ('allow-notify {\n' + functions.simple_item_list(item.options.allow_notify) + '};\n') if item.options.allow_notify is defined and item.options.allow_notify -}} +{{ ('allow-query {\n' + functions.simple_item_list(item.options.allow_query) + '};\n') if item.options.allow_query is defined and item.options.allow_query -}} +{{ ('allow-query-cache {\n' + functions.simple_item_list(item.options.allow_query_cache) + '};\n') if item.options.allow_query_cache is defined and item.options.allow_query_cache -}} +{{ ('allow-query-cache-on {\n' + functions.simple_item_list(item.options.allow_query_cache_on) + '};\n') if item.options.allow_query_cache_on is defined and item.options.allow_query_cache_on -}} +{{ ('allow-query-on {\n' + functions.simple_item_list(item.options.allow_query_on) + '};\n') if item.options.allow_query_on is defined and item.options.allow_query_on -}} +{{ ('allow-recursion {\n' + functions.simple_item_list(item.options.allow_recursion) + '};\n') if item.options.allow_recursion is defined and item.options.allow_recursion -}} +{{ ('allow-recursion-on {\n' + functions.simple_item_list(item.options.allow_recursion_on) + '};\n') if item.options.allow_recursion_on is defined and item.options.allow_recursion_on -}} +{{ ('allow-update {\n' + functions.simple_item_list(item.options.allow_update) + '};\n') if item.options.allow_update is defined and item.options.allow_update -}} +{{ ('allow-update-forwarding {\n' + functions.simple_item_list(item.options.allow_update_forwarding) + '};\n') if item.options.allow_update_forwarding is defined and item.options.allow_update_forwarding -}} +{{ ('blackhole {\n' + functions.simple_item_list(item.options.blackhole) + '};\n') if item.options.blackhole is defined and item.options.blackhole -}} +{{ ('keep-response-order {\n' + functions.simple_item_list(item.options.keep_response_order) + '};\n') if item.options.keep_response_order is defined and item.options.keep_response_order -}} +{{ ('no-case-compress {\n' + functions.simple_item_list(item.options.no_case_compress) + '};\n') if item.options.no_case_compress is defined and item.options.no_case_compress -}} +{{ ('sortlist {\n' + functions.simple_item_list(item.options.sortlist) + '};\n') if item.options.sortlist is defined and item.options.sortlist -}} +{# String options #} +{{ ('attach-cache ' + item.options.attach_cache | string +';\n') if item.options.attach_cache is defined and item.options.attach_cache -}} +{{ ('cookie-secret ' + item.options.cookie_secret | string +';\n') if item.options.cookie_secret is defined and item.options.cookie_secret -}} +{{ ('disable-empty-zone ' + item.options.disable_empty_zone | string +';\n') if item.options.disable_empty_zone is defined and item.options.disable_empty_zone -}} +{{ ('dns64-contact ' + item.options.dns64_contact | string +';\n') if item.options.dns64_contact is defined and item.options.dns64_contact -}} +{{ ('dns64-server ' + item.options.dns64_server | string +';\n') if item.options.dns64_server is defined and item.options.dns64_server -}} +{{ ('dnssec-policy ' + item.options.dnssec_policy | string +';\n') if item.options.dnssec_policy is defined and item.options.dnssec_policy -}} +{{ ('empty-contact ' + item.options.empty_contact | string +';\n') if item.options.empty_contact is defined and item.options.empty_contact -}} +{{ ('empty-server ' + item.options.empty_server | string +';\n') if item.options.empty_server is defined and item.options.empty_server -}} +{{ ('ipv4only-contact ' + item.options.ipv4only_contact | string +';\n') if item.options.ipv4only_contact is defined and item.options.ipv4only_contact -}} +{{ ('ipv4only-server ' + item.options.ipv4only_server | string +';\n') if item.options.ipv4only_server is defined and item.options.ipv4only_server -}} +{{ ('nxdomain-redirect ' + item.options.nxdomain_redirect | string +';\n') if item.options.nxdomain_redirect is defined and item.options.nxdomain_redirect -}} +{{ ('preferred-glue ' + item.options.preferred_glue | string +';\n') if item.options.preferred_glue is defined and item.options.preferred_glue -}} +{{ ('session-keyalg ' + item.options.session_keyalg | string +';\n') if item.options.session_keyalg is defined and item.options.session_keyalg -}} +{{ ('session-keyname ' + item.options.session_keyname | string +';\n') if item.options.session_keyname is defined and item.options.session_keyname -}} +{# Integer options #} +{{ ('clients-per-query ' + item.options.clients_per_query | string +';\n') if item.options.clients_per_query is defined and item.options.clients_per_query -}} +{{ ('dnskey-sig-validity ' + item.options.dnskey_sig_validity | string +';\n') if item.options.dnskey_sig_validity is defined and item.options.dnskey_sig_validity -}} +{{ ('dnssec-loadkeys-interval ' + item.options.dnssec_loadkeys_interval | string +';\n') if item.options.dnssec_loadkeys_interval is defined and item.options.dnssec_loadkeys_interval -}} +{{ ('dscp ' + item.options.dscp | string +';\n') if item.options.dscp is defined and item.options.dscp -}} +{{ ('edns-udp-size ' + item.options.edns_udp_size | string +';\n') if item.options.edns_udp_size is defined and item.options.edns_udp_size -}} +{{ ('fstrm-set-buffer-hint ' + item.options.fstrm_set_buffer_hint | string +';\n') if item.options.fstrm_set_buffer_hint is defined and item.options.fstrm_set_buffer_hint -}} +{{ ('fstrm-set-flush-timeout ' + item.options.fstrm_set_flush_timeout | string +';\n') if item.options.fstrm_set_flush_timeout is defined and item.options.fstrm_set_flush_timeout -}} +{{ ('fstrm-set-input-queue-size ' + item.options.fstrm_set_input_queue_size | string +';\n') if item.options.fstrm_set_input_queue_size is defined and item.options.fstrm_set_input_queue_size -}} +{{ ('fstrm-set-output-notify-threshold ' + item.options.fstrm_set_output_notify_threshold | string +';\n') if item.options.fstrm_set_output_notify_threshold is defined and item.options.fstrm_set_output_notify_threshold -}} +{{ ('fstrm-set-output-queue-size ' + item.options.fstrm_set_output_queue_size | string +';\n') if item.options.fstrm_set_output_queue_size is defined and item.options.fstrm_set_output_queue_size -}} +{{ ('heartbeat-interval ' + item.options.heartbeat_interval | string +';\n') if item.options.heartbeat_interval is defined and item.options.heartbeat_interval -}} +{{ ('http-listener-clients ' + item.options.http_listener_clients | string +';\n') if item.options.http_listener_clients is defined and item.options.http_listener_clients -}} +{{ ('http-port ' + item.options.http_port | string +';\n') if item.options.http_port is defined and item.options.http_port -}} +{{ ('http-streams-per-connection ' + item.options.http_streams_per_connection | string +';\n') if item.options.http_streams_per_connection is defined and item.options.http_streams_per_connection -}} +{{ ('https-port ' + item.options.https_port | string +';\n') if item.options.https_port is defined and item.options.https_port -}} +{{ ('max-clients-per-query ' + item.options.max_clients_per_query | string +';\n') if item.options.max_clients_per_query is defined and item.options.max_clients_per_query -}} +{{ ('max-records ' + item.options.max_records | string +';\n') if item.options.max_records is defined and item.options.max_records -}} +{{ ('max-recursion-depth ' + item.options.max_recursion_depth | string +';\n') if item.options.max_recursion_depth is defined and item.options.max_recursion_depth -}} +{{ ('max-recursion-queries ' + item.options.max_recursion_queries | string +';\n') if item.options.max_recursion_queries is defined and item.options.max_recursion_queries -}} +{{ ('max-refresh-time ' + item.options.max_refresh_time | string +';\n') if item.options.max_refresh_time is defined and item.options.max_refresh_time -}} +{{ ('max-retry-time ' + item.options.max_retry_time | string +';\n') if item.options.max_retry_time is defined and item.options.max_retry_time -}} +{{ ('max-rsa-exponent-size ' + item.options.max_rsa_exponent_size | string +';\n') if item.options.max_rsa_exponent_size is defined and item.options.max_rsa_exponent_size -}} +{{ ('max-transfer-idle-in ' + item.options.max_transfer_idle_in | string +';\n') if item.options.max_transfer_idle_in is defined and item.options.max_transfer_idle_in -}} +{{ ('max-transfer-idle-out ' + item.options.max_transfer_idle_out | string +';\n') if item.options.max_transfer_idle_out is defined and item.options.max_transfer_idle_out -}} +{{ ('max-transfer-time-in ' + item.options.max_transfer_time_in | string +';\n') if item.options.max_transfer_time_in is defined and item.options.max_transfer_time_in -}} +{{ ('max-transfer-time-out ' + item.options.max_transfer_time_out | string +';\n') if item.options.max_transfer_time_out is defined and item.options.max_transfer_time_out -}} +{{ ('max-udp-size ' + item.options.max_udp_size | string +';\n') if item.options.max_udp_size is defined and item.options.max_udp_size -}} +{{ ('min-refresh-time ' + item.options.min_refresh_time | string +';\n') if item.options.min_refresh_time is defined and item.options.min_refresh_time -}} +{{ ('min-retry-time ' + item.options.min_retry_time | string +';\n') if item.options.min_retry_time is defined and item.options.min_retry_time -}} +{{ ('nocookie-udp-size ' + item.options.nocookie_udp_size | string +';\n') if item.options.nocookie_udp_size is defined and item.options.nocookie_udp_size -}} +{{ ('notify-delay ' + item.options.notify_delay | string +';\n') if item.options.notify_delay is defined and item.options.notify_delay -}} +{{ ('notify-rate ' + item.options.notify_rate | string +';\n') if item.options.notify_rate is defined and item.options.notify_rate -}} +{{ ('port ' + item.options.port | string +';\n') if item.options.port is defined and item.options.port -}} +{{ ('recursive-clients ' + item.options.recursive_clients | string +';\n') if item.options.recursive_clients is defined and item.options.recursive_clients -}} +{{ ('resolver-nonbackoff-tries ' + item.options.resolver_nonbackoff_tries | string +';\n') if item.options.resolver_nonbackoff_tries is defined and item.options.resolver_nonbackoff_tries -}} +{{ ('resolver-query-timeout ' + item.options.resolver_query_timeout | string +';\n') if item.options.resolver_query_timeout is defined and item.options.resolver_query_timeout -}} +{{ ('resolver-retry-interval ' + item.options.resolver_retry_interval | string +';\n') if item.options.resolver_retry_interval is defined and item.options.resolver_retry_interval -}} +{{ ('serial-query-rate ' + item.options.serial_query_rate | string +';\n') if item.options.serial_query_rate is defined and item.options.serial_query_rate -}} +{{ ('sig-signing-nodes ' + item.options.sig_signing_nodes | string +';\n') if item.options.sig_signing_nodes is defined and item.options.sig_signing_nodes -}} +{{ ('sig-signing-signatures ' + item.options.sig_signing_signatures | string +';\n') if item.options.sig_signing_signatures is defined and item.options.sig_signing_signatures -}} +{{ ('sig-signing-type ' + item.options.sig_signing_type | string +';\n') if item.options.sig_signing_type is defined and item.options.sig_signing_type -}} +{{ ('startup-notify-rate ' + item.options.startup_notify_rate | string +';\n') if item.options.startup_notify_rate is defined and item.options.startup_notify_rate -}} +{{ ('tcp-advertised-timeout ' + item.options.tcp_advertised_timeout | string +';\n') if item.options.tcp_advertised_timeout is defined and item.options.tcp_advertised_timeout -}} +{{ ('tcp-clients ' + item.options.tcp_clients | string +';\n') if item.options.tcp_clients is defined and item.options.tcp_clients -}} +{{ ('tcp-idle-timeout ' + item.options.tcp_idle_timeout | string +';\n') if item.options.tcp_idle_timeout is defined and item.options.tcp_idle_timeout -}} +{{ ('tcp-initial-timeout ' + item.options.tcp_initial_timeout | string +';\n') if item.options.tcp_initial_timeout is defined and item.options.tcp_initial_timeout -}} +{{ ('tcp-keepalive-timeout ' + item.options.tcp_keepalive_timeout | string +';\n') if item.options.tcp_keepalive_timeout is defined and item.options.tcp_keepalive_timeout -}} +{{ ('tcp-listen-queue ' + item.options.tcp_listen_queue | string +';\n') if item.options.tcp_listen_queue is defined and item.options.tcp_listen_queue -}} +{{ ('tcp-receive-buffer ' + item.options.tcp_receive_buffer | string +';\n') if item.options.tcp_receive_buffer is defined and item.options.tcp_receive_buffer -}} +{{ ('tcp-send-buffer ' + item.options.tcp_send_buffer | string +';\n') if item.options.tcp_send_buffer is defined and item.options.tcp_send_buffer -}} +{{ ('tls-port ' + item.options.tls_port | string +';\n') if item.options.tls_port is defined and item.options.tls_port -}} +{{ ('transfer-message-size ' + item.options.transfer_message_size | string +';\n') if item.options.transfer_message_size is defined and item.options.transfer_message_size -}} +{{ ('transfers-in ' + item.options.transfers_in | string +';\n') if item.options.transfers_in is defined and item.options.transfers_in -}} +{{ ('transfers-out ' + item.options.transfers_out | string +';\n') if item.options.transfers_out is defined and item.options.transfers_out -}} +{{ ('transfers-per-ns ' + item.options.transfers_per_ns | string +';\n') if item.options.transfers_per_ns is defined and item.options.transfers_per_ns -}} +{{ ('udp-receive-buffer ' + item.options.udp_receive_buffer | string +';\n') if item.options.udp_receive_buffer is defined and item.options.udp_receive_buffer -}} +{{ ('udp-send-buffer ' + item.options.udp_send_buffer | string +';\n') if item.options.udp_send_buffer is defined and item.options.udp_send_buffer -}} +{{ ('v6-bias ' + item.options.v6_bias | string +';\n') if item.options.v6_bias is defined and item.options.v6_bias -}} +{# Boolean options #} +{{ (functions.boolean_option('allow-new-zones', item.options.allow_new_zones) + '\n') if item.options.allow_new_zones is defined -}} +{{ (functions.boolean_option('answer-cookie', item.options.answer_cookie) + '\n') if item.options.answer_cookie is defined -}} +{{ (functions.boolean_option('auth-nxdomain', item.options.auth_nxdomain) + '\n') if item.options.auth_nxdomain is defined -}} +{{ (functions.boolean_option('automatic-interface-scan', item.options.automatic_interface_scan) + '\n') if item.options.automatic_interface_scan is defined -}} +{{ (functions.boolean_option('check-integrity', item.options.check_integrity) + '\n') if item.options.check_integrity is defined -}} +{{ (functions.boolean_option('check-sibling', item.options.check_sibling) + '\n') if item.options.check_sibling is defined -}} +{{ (functions.boolean_option('check-wildcard', item.options.check_wildcard) + '\n') if item.options.check_wildcard is defined -}} +{{ (functions.boolean_option('dnsrps-enable', item.options.dnsrps_enable) + '\n') if item.options.dnsrps_enable is defined -}} +{{ (functions.boolean_option('dnssec-accept-expired', item.options.dnssec_accept_expired) + '\n') if item.options.dnssec_accept_expired is defined -}} +{{ (functions.boolean_option('dnssec-dnskey-kskonly', item.options.dnssec_dnskey_kskonly) + '\n') if item.options.dnssec_dnskey_kskonly is defined -}} +{{ (functions.boolean_option('dnssec-secure-to-insecure', item.options.dnssec_secure_to_insecure) + '\n') if item.options.dnssec_secure_to_insecure is defined -}} +{{ (functions.boolean_option('empty-zones-enable', item.options.empty_zones_enable) + '\n') if item.options.empty_zones_enable is defined -}} +{{ (functions.boolean_option('flush-zones-on-shutdown', item.options.flush_zones_on_shutdown) + '\n') if item.options.flush_zones_on_shutdown is defined -}} +{{ (functions.boolean_option('glue-cache', item.options.glue_cache) + '\n') if item.options.glue_cache is defined -}} +{{ (functions.boolean_option('ipv4only-enable', item.options.ipv4only_enable) + '\n') if item.options.ipv4only_enable is defined -}} +{{ (functions.boolean_option('match-mapped-addresses', item.options.match_mapped_addresses) + '\n') if item.options.match_mapped_addresses is defined -}} +{{ (functions.boolean_option('memstatistics', item.options.memstatistics) + '\n') if item.options.memstatistics is defined -}} +{{ (functions.boolean_option('message-compression', item.options.message_compression) + '\n') if item.options.message_compression is defined -}} +{{ (functions.boolean_option('minimal-any', item.options.minimal_any) + '\n') if item.options.minimal_any is defined -}} +{{ (functions.boolean_option('multi-master', item.options.multi_master) + '\n') if item.options.multi_master is defined -}} +{{ (functions.boolean_option('notify-to-soa', item.options.notify_to_soa) + '\n') if item.options.notify_to_soa is defined -}} +{{ (functions.boolean_option('provide-ixfr', item.options.provide_ixfr) + '\n') if item.options.provide_ixfr is defined -}} +{{ (functions.boolean_option('querylog', item.options.querylog) + '\n') if item.options.querylog is defined -}} +{{ (functions.boolean_option('recursion', item.options.recursion) + '\n') if item.options.recursion is defined -}} +{{ (functions.boolean_option('request-expire', item.options.request_expire) + '\n') if item.options.request_expire is defined -}} +{{ (functions.boolean_option('request-ixfr', item.options.request_ixfr) + '\n') if item.options.request_ixfr is defined -}} +{{ (functions.boolean_option('request-nsid', item.options.request_nsid) + '\n') if item.options.request_nsid is defined -}} +{{ (functions.boolean_option('require-server-cookie', item.options.require_server_cookie) + '\n') if item.options.require_server_cookie is defined -}} +{{ (functions.boolean_option('reuseport', item.options.reuseport) + '\n') if item.options.reuseport is defined -}} +{{ (functions.boolean_option('root-key-sentinel', item.options.root_key_sentinel) + '\n') if item.options.root_key_sentinel is defined -}} +{{ (functions.boolean_option('send-cookie', item.options.send_cookie) + '\n') if item.options.send_cookie is defined -}} +{{ (functions.boolean_option('stale-answer-enable', item.options.stale_answer_enable) + '\n') if item.options.stale_answer_enable is defined -}} +{{ (functions.boolean_option('stale-cache-enable', item.options.stale_cache_enable) + '\n') if item.options.stale_cache_enable is defined -}} +{{ (functions.boolean_option('synth-from-dnssec', item.options.synth_from_dnssec) + '\n') if item.options.synth_from_dnssec is defined -}} +{{ (functions.boolean_option('trust-anchor-telemetry', item.options.trust_anchor_telemetry) + '\n') if item.options.trust_anchor_telemetry is defined -}} +{{ (functions.boolean_option('try-tcp-refresh', item.options.try_tcp_refresh) + '\n') if item.options.try_tcp_refresh is defined -}} +{{ (functions.boolean_option('update-check-ksk', item.options.update_check_ksk) + '\n') if item.options.update_check_ksk is defined -}} +{{ (functions.boolean_option('use-alt-transfer-source', item.options.use_alt_transfer_source) + '\n') if item.options.use_alt_transfer_source is defined -}} +{{ (functions.boolean_option('zero-no-soa-ttl', item.options.zero_no_soa_ttl) + '\n') if item.options.zero_no_soa_ttl is defined -}} +{{ (functions.boolean_option('zero-no-soa-ttl-cache', item.options.zero_no_soa_ttl_cache) + '\n') if item.options.zero_no_soa_ttl_cache is defined -}} {% endfilter %} }; + diff --git a/templates/named.conf.remote-servers.j2 b/templates/named.conf.remote-servers.j2 deleted file mode 100644 index 08b1fe3..0000000 --- a/templates/named.conf.remote-servers.j2 +++ /dev/null @@ -1,20 +0,0 @@ -{% for server in item.remote_servers %} -remote-servers "{{ server.name }}" { -{% filter indent(bind9_config_indent, true) %} -{% for key, value in server.items() %} -{% if key != 'name' %} -{# Handle known complex types if any, otherwise default to simple string/block #} -{% if value is iterable and value is not string and value is not mapping %} -{{ key }} { - {% for subitem in value %} - {{ subitem }}; - {% endfor %} -}; -{% else %} -{{ key }} {{ value }}; -{% endif %} -{% endif %} -{% endfor %} -{% endfilter %} -}; -{% endfor %} diff --git a/templates/named.conf.zone.j2 b/templates/named.conf.zone.j2 index e73704a..0423220 100644 --- a/templates/named.conf.zone.j2 +++ b/templates/named.conf.zone.j2 @@ -2,20 +2,29 @@ zone "{{ zone.name }}" { {% filter indent(bind9_config_indent, true) %} -{% for key, value in zone.items() %} -{% set conf_key = key | replace('_', '-') %} - -{% if key == 'name' %} -{# Skip name as it is in the zone header #} - -{# --- COMPLEX BLOCKS --- #} -{% elif key == 'update_policy' %} -{% if value == 'local' %} +# Zone {{ zone.name }} type {{ zone.type }} +{# Most critical/defining statements first #} +{{ ('type ' + zone.type | string+';\n') if zone.type is defined and zone.type -}} +{{ ('file "' + zone.file | string+'";\n') if zone.file is defined and zone.file -}} +{{ ('forward ' + zone.forward | string+';\n') if zone.forward is defined and zone.forward -}} +{{ ('journal "' + zone.journal | string+'";\n') if zone.journal is defined and zone.journal -}} +{{ ('key-directory "' + zone.key_directory | string+'";\n') if zone.key_directory is defined and zone.key_directory -}} +{# boolean_or_string options #} +{{ ('dialup ' + functions.boolean_or_string(zone.dialup) + ';\n') if zone.dialup is defined -}} +{{ ('notify ' + functions.boolean_or_string(zone.notify) + ';\n') if zone.notify is defined -}} +{{ ('zone-statistics ' + functions.boolean_or_string(zone.zone_statistics) + ';\n') if zone.zone_statistics is defined -}} +{# upstream_servers options #} +{{ functions.parent_address_key_tls('also-notify', zone.also_notify) if zone.also_notify is defined and zone.also_notify -}} +{{ functions.parent_address_key_tls('primaries', zone.primaries) if zone.primaries is defined and zone.primaries -}} +{{ functions.parent_address_key_tls('parental-agents', zone.parental_agents) if zone.parental_agents is defined and zone.parental_agents -}} +{# Unicorn Options#} +{% if zone.update_policy is defined and zone.update_policy %} +{% if zone.update_policy == 'local' %} update-policy local; {% else %} update-policy { {% filter indent(bind9_config_indent, true) %} -{% for policy in value %} +{% for policy in zone.update_policy %} {{ policy.permission -}} {{ ' ' + policy.identity -}} {{ ' ' + policy.ruletype -}} @@ -24,61 +33,127 @@ update-policy { {% endfor %} {% endfilter %}}; {% endif %} - -{% elif key == 'sig_validity_interval' %} -sig-validity-interval -{{- (' ' + value.upper | string) }} -{{- (' ' + value.lower | string) if value.lower is defined and value.lower -}}; - -{% elif key in ['server_names', 'server_addresses'] %} -{{ conf_key }} { -{{ functions.simple_item_list(value) }}}; - -{% elif key in ['also_notify', 'primaries', 'parental_agents'] %} -{{ functions.parent_address_key_tls(conf_key, value) -}} - -{% elif key == 'forwarders' %} -{{ functions.parent_address_port_dscp('forwarders', value) -}} - -{% elif key == 'allow_transfer' and value is not string and value is mapping %} -allow-transfer -{{- (' port ' + value.port | string) if value.port is defined and value.port -}} -{{- (' transport ' + value.transport) if value.transport is defined and value.transport }} { -{{ functions.simple_item_list(value.addresses) }}}; - -{% elif key in ['transfer_source', 'transfer_source_v6', 'alt_transfer_source', 'alt_transfer_source_v6', 'notify_source', 'notify_source_v6', 'parental_source', 'parental_source_v6'] %} -{{ conf_key }} {{ value.address -}} -{{- (' port ' + value.port | string) if value.port is defined and value.port -}} -{{- (' dscp ' + value.dscp | string) if value.dscp is defined and value.dscp }}; - -{# --- SIMPLE LISTS --- #} -{% elif key in ['allow_notify', 'allow_query', 'allow_query_on', 'allow_update', 'allow_update_forwarding'] %} -{{ conf_key }} { -{{ functions.simple_item_list(value) }}}; - -{# --- BOOLEANS --- #} -{% elif key in ['check_integrity', 'check_sibling', 'check_wildcard', 'delegation_only', 'dnssec_dnskey_kskonly', 'dnssec_secure_to_insecure', 'inline_signing', 'ixfr_from_differences', 'multi_master', 'notify_to_soa', 'request_expire', 'request_ixfr', 'try_tcp_refresh', 'update_check_ksk', 'use_alt_transfer_source', 'zero_no_soa_ttl'] %} -{{ (functions.boolean_option(conf_key, value)) }} - -{# --- BOOLEAN OR STRING --- #} -{% elif key in ['dialup', 'notify', 'zone_statistics'] %} -{{ conf_key }} {{ functions.boolean_or_string(value) }}; - -{# --- QUOTED STRINGS --- #} -{% elif key in ['file', 'journal', 'key_directory'] %} -{{ conf_key }} "{{ value }}"; - -{# --- DEPRECATED --- #} -{% elif key == 'auto_dnssec' %} -/* WARN: auto-dnssec is removed in BIND 9.20 */ -{{ conf_key }} {{ value }}; - -{# --- FALLTHROUGH --- #} -{% else %} -{# Strict mode: Ignore unknown keys #} {% endif %} - -{% endfor %} +{% if zone.sig_validity_interval is defined and zone.sig_validity_interval %} +sig-validity-interval +{{- (' ' + zone.sig_validity_interval.upper | string) }} +{{- (' ' + zone.sig_validity_interval.lower | string) if zone.sig_validity_interval.lower is defined and zone.sig_validity_interval.lower -}}; +{% endif %} +{% if zone.server_names is defined and zone.server_names %} +server-names { +{{ functions.simple_item_list(zone.server_names) }}}; +{% endif %} +{% if zone.server_addresses is defined and zone.server_addresses %} +server-addresses { +{{ functions.simple_item_list(zone.server_addresses) }}}; +{% endif %} +{{ functions.parent_address_port_dscp('forwarders', zone.forwarders) if zone.forwarders is defined and zone.forwarders -}} +{% if zone.allow_transfer is defined and zone.allow_transfer is not string %} +allow-transfer +{{- (' port ' + zone.allow_transfer.port | string) if zone.allow_transfer.port is defined and zone.allow_transfer.port -}} +{{- (' transport ' + zone.allow_transfer.transport) if zone.allow_transfer.transport is defined and zone.allow_transfer.transport }} { +{{ functions.simple_item_list(zone.allow_transfer.addresses) }}}; +{% endif %} +{# simple_list options #} +{{ ('allow-notify {\n' + functions.simple_item_list(zone.allow_notify) + '};\n') if zone.allow_notify is defined and zone.allow_notify -}} +{{ ('allow-query {\n' + functions.simple_item_list(zone.allow_query) + '};\n') if zone.allow_query is defined and zone.allow_query -}} +{{ ('allow-query-on {\n' + functions.simple_item_list(zone.allow_query_on) + '};\n') if zone.allow_query_on is defined and zone.allow_query_on -}} +{{ ('allow-update {\n' + functions.simple_item_list(zone.allow_update) + '};\n') if zone.allow_update is defined and zone.allow_update -}} +{{ ('allow-update-forwarding {\n' + functions.simple_item_list(zone.allow_update_forwarding) + '};\n') if zone.allow_update_forwarding is defined and zone.allow_update_forwarding -}} +{# ip_port_dscp options#} +{% if zone.transfer_source is defined and zone.transfer_source is mapping %} +transfer-source {{ zone.transfer_source.address -}} +{{- (' port ' + zone.transfer_source.port | string) if zone.transfer_source.port is defined and zone.transfer_source.port -}} +{{- (' dscp ' + zone.transfer_source.dscp | string) if zone.transfer_source.dscp is defined and zone.transfer_source.dscp }}; +{% endif %} +{% if zone.transfer_source_v6 is defined and zone.transfer_source_v6 is mapping %} +transfer-source-v6 {{ zone.transfer_source_v6.address -}} +{{- (' port ' + zone.transfer_source_v6.port | string) if zone.transfer_source_v6.port is defined and zone.transfer_source_v6.port -}} +{{- (' dscp ' + zone.transfer_source_v6.dscp | string) if zone.transfer_source_v6.dscp is defined and zone.transfer_source_v6.dscp }}; +{% endif %} +{% if zone.alt_transfer_source is defined and zone.alt_transfer_source is mapping %} +alt-transfer-source {{ zone.alt_transfer_source.address -}} +{{- (' port ' + zone.alt_transfer_source.port | string) if zone.alt_transfer_source.port is defined and zone.alt_transfer_source.port -}} +{{- (' dscp ' + zone.alt_transfer_source.dscp | string) if zone.alt_transfer_source.dscp is defined and zone.alt_transfer_source.dscp }}; +{% endif %} +{% if zone.alt_transfer_source_v6 is defined and zone.alt_transfer_source_v6 is mapping %} +alt-transfer-source-v6 {{ zone.alt_transfer_source_v6.address -}} +{{- (' port ' + zone.alt_transfer_source_v6.port | string) if zone.alt_transfer_source_v6.port is defined and zone.alt_transfer_source_v6.port -}} +{{- (' dscp ' + zone.alt_transfer_source_v6.dscp | string) if zone.alt_transfer_source_v6.dscp is defined and zone.alt_transfer_source_v6.dscp }}; +{% endif %} +{% if zone.notify_source is defined and zone.notify_source is mapping %} +notify-source {{ zone.notify_source.address -}} +{{- (' port ' + zone.notify_source.port | string) if zone.notify_source.port is defined and zone.notify_source.port -}} +{{- (' dscp ' + zone.notify_source.dscp | string) if zone.notify_source.dscp is defined and zone.notify_source.dscp }}; +{% endif %} +{% if zone.notify_source_v6 is defined and zone.notify_source_v6 is mapping %} +notify-source-v6 {{ zone.notify_source_v6.address -}} +{{- (' port ' + zone.notify_source_v6.port | string) if zone.notify_source_v6.port is defined and zone.notify_source_v6.port -}} +{{- (' dscp ' + zone.notify_source_v6.dscp | string) if zone.notify_source_v6.dscp is defined and zone.notify_source_v6.dscp }}; +{% endif %} +{% if zone.parental_source is defined and zone.parental_source is mapping %} +parental-source {{ zone.parental_source.address -}} +{{- (' port ' + zone.parental_source.port | string) if zone.parental_source.port is defined and zone.parental_source.port -}} +{{- (' dscp ' + zone.parental_source.dscp | string) if zone.parental_source.dscp is defined and zone.parental_source.dscp }}; +{% endif %} +{% if zone.parental_source_v6 is defined and zone.parental_source_v6 is mapping %} +parental-source-v6 {{ zone.parental_source_v6.address -}} +{{- (' port ' + zone.parental_source_v6.port | string) if zone.parental_source_v6.port is defined and zone.parental_source_v6.port -}} +{{- (' dscp ' + zone.parental_source_v6.dscp | string) if zone.parental_source_v6.dscp is defined and zone.parental_source_v6.dscp }}; +{% endif %} +{# integer options #} +{{ ('dnskey-sig-validity ' + zone.dnskey_sig_validity | string+';\n') if zone.dnskey_sig_validity is defined and zone.dnskey_sig_validity -}} +{{ ('dnssec-loadkeys-interval ' + zone.dnssec_loadkeys_interval | string+';\n') if zone.dnssec_loadkeys_interval is defined and zone.dnssec_loadkeys_interval -}} +{{ ('max-records ' + zone.max_records | string+';\n') if zone.max_records is defined and zone.max_records -}} +{{ ('max-refresh-time ' + zone.max_refresh_time | string+';\n') if zone.max_refresh_time is defined and zone.max_refresh_time -}} +{{ ('max-retry-time ' + zone.max_retry_time | string+';\n') if zone.max_retry_time is defined and zone.max_retry_time -}} +{{ ('max-transfer-idle-in ' + zone.max_transfer_idle_in | string+';\n') if zone.max_transfer_idle_in is defined and zone.max_transfer_idle_in -}} +{{ ('max-transfer-idle-out ' + zone.max_transfer_idle_out | string+';\n') if zone.max_transfer_idle_out is defined and zone.max_transfer_idle_out -}} +{{ ('max-transfer-time-in ' + zone.max_transfer_time_in | string+';\n') if zone.max_transfer_time_in is defined and zone.max_transfer_time_in -}} +{{ ('max-transfer-time-out ' + zone.max_transfer_time_out | string+';\n') if zone.max_transfer_time_out is defined and zone.max_transfer_time_out -}} +{{ ('min-refresh-time ' + zone.min_refresh_time | string+';\n') if zone.min_refresh_time is defined and zone.min_refresh_time -}} +{{ ('min-retry-time ' + zone.min_retry_time | string+';\n') if zone.min_retry_time is defined and zone.min_retry_time -}} +{{ ('notify-delay ' + zone.notify_delay | string+';\n') if zone.notify_delay is defined and zone.notify_delay -}} +{{ ('sig-signing-nodes ' + zone.sig_signing_nodes | string+';\n') if zone.sig_signing_nodes is defined and zone.sig_signing_nodes -}} +{{ ('sig-signing-signatures ' + zone.sig_signing_signatures | string+';\n') if zone.sig_signing_signatures is defined and zone.sig_signing_signatures -}} +{{ ('sig-signing-type ' + zone.sig_signing_type | string+';\n') if zone.sig_signing_type is defined and zone.sig_signing_type -}} +{# boolean options #} +{{ (functions.boolean_option('check-integrity', zone.check_integrity) + '\n') if zone.check_integrity is defined -}} +{{ (functions.boolean_option('check-sibling', zone.check_sibling) + '\n') if zone.check_sibling is defined -}} +{{ (functions.boolean_option('check-wildcard', zone.check_wildcard) + '\n') if zone.check_wildcard is defined -}} +{{ (functions.boolean_option('delegation-only', zone.delegation_only) + '\n') if zone.delegation_only is defined -}} +{{ (functions.boolean_option('dnssec-dnskey-kskonly', zone.dnssec_dnskey_kskonly) + '\n') if zone.dnssec_dnskey_kskonly is defined -}} +{{ (functions.boolean_option('dnssec-secure-to-insecure', zone.dnssec_secure_to_insecure) + '\n') if zone.dnssec_secure_to_insecure is defined -}} +{{ (functions.boolean_option('inline-signing', zone.inline_signing) + '\n') if zone.inline_signing is defined -}} +{{ (functions.boolean_option('ixfr-from-differences', zone.ixfr_from_differences) + '\n') if zone.ixfr_from_differences is defined -}} +{{ (functions.boolean_option('multi-master', zone.multi_master) + '\n') if zone.multi_master is defined -}} +{{ (functions.boolean_option('notify-to-soa', zone.notify_to_soa) + '\n') if zone.notify_to_soa is defined -}} +{{ (functions.boolean_option('request-expire', zone.request_expire) + '\n') if zone.request_expire is defined -}} +{{ (functions.boolean_option('request-ixfr', zone.request_ixfr) + '\n') if zone.request_ixfr is defined -}} +{{ (functions.boolean_option('try-tcp-refresh', zone.try_tcp_refresh) + '\n') if zone.try_tcp_refresh is defined -}} +{{ (functions.boolean_option('update-check-ksk', zone.update_check_ksk) + '\n') if zone.update_check_ksk is defined -}} +{{ (functions.boolean_option('use-alt-transfer-source', zone.use_alt_transfer_source) + '\n') if zone.use_alt_transfer_source is defined -}} +{{ (functions.boolean_option('zero-no-soa-ttl', zone.zero_no_soa_ttl) + '\n') if zone.zero_no_soa_ttl is defined -}} +{# multiple_choice options #} +{{ ('auto-dnssec ' + zone.auto_dnssec | string+';\n') if zone.auto_dnssec is defined and zone.auto_dnssec -}} +{{ ('check-dup-records ' + zone.check_dup_records | string+';\n') if zone.check_dup_records is defined and zone.check_dup_records -}} +{{ ('check-mx-cname ' + zone.check_mx_cname | string+';\n') if zone.check_mx_cname is defined and zone.check_mx_cname -}} +{{ ('check-mx ' + zone.check_mx | string+';\n') if zone.check_mx is defined and zone.check_mx -}} +{{ ('check-names ' + zone.check_names | string+';\n') if zone.check_names is defined and zone.check_names -}} +{{ ('check-spf ' + zone.check_spf | string+';\n') if zone.check_spf is defined and zone.check_spf -}} +{{ ('check-srv-cname ' + zone.check_srv_cname | string+';\n') if zone.check_srv_cname is defined and zone.check_srv_cname -}} +{{ ('dnssec-update-mode ' + zone.dnssec_update_mode | string+';\n') if zone.dnssec_update_mode is defined and zone.dnssec_update_mode -}} +{{ ('masterfile-format ' + zone.masterfile_format | string+';\n') if zone.masterfile_format is defined and zone.masterfile_format -}} +{{ ('masterfile-style ' + zone.masterfile_style | string+';\n') if zone.masterfile_style is defined and zone.masterfile_style -}} +{{ ('max-ixfr-ratio ' + zone.max_ixfr_ratio | string+';\n') if zone.max_ixfr_ratio is defined and zone.max_ixfr_ratio -}} +{{ ('max-journal-size ' + zone.max_journal_size | string+';\n') if zone.max_journal_size is defined and zone.max_journal_size -}} +{{ ('max-zone-ttl ' + zone.max_zone_ttl | string+';\n') if zone.max_zone_ttl is defined and zone.max_zone_ttl -}} +{{ ('serial-update-method ' + zone.serial_update_method | string+';\n') if zone.serial_update_method is defined and zone.serial_update_method -}} +{# string options #} +{{ ('database ' + zone.database | string+';\n') if zone.database is defined and zone.database -}} +{{ ('dlz ' + zone.dlz | string+';\n') if zone.dlz is defined and zone.dlz -}} +{{ ('dnssec-policy ' + zone.dnssec_policy | string+';\n') if zone.dnssec_policy is defined and zone.dnssec_policy -}} +{{ ('in-view ' + zone.in_view | string+';\n') if zone.in_view is defined and zone.in_view -}} {% endfilter %} }; {% endfor %} From d59001964b8124ee83eacfb66ed71f433a4f92c8 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Thu, 22 Jan 2026 22:36:25 +0000 Subject: [PATCH 07/11] revert 986b33df21c238f1df50b2fcd8bdfc89a71f3137 revert fix: explicit boolean checks for Ansible 12 compatibility From 4084573f2b046135537985197f3a414cdd5f1019 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Thu, 22 Jan 2026 22:36:43 +0000 Subject: [PATCH 08/11] revert 192747e438816abb8d4a29b750feeb2601eb7b60 revert refactor: Rename leaf config to site config feat: Add argument specs and atomic validation From 421922729d5ceb28d33d427bbc7d8400072a16e2 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Thu, 22 Jan 2026 22:36:50 +0000 Subject: [PATCH 09/11] revert b5a9e977124342c1905f36d10ab2e489c0ecb71d revert refactor: Update templates to use dynamic ordering and add deprecation warnings From f2e493833656fd8e3ebd1bc3701afdbdea6abe2b Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Thu, 22 Jan 2026 22:36:55 +0000 Subject: [PATCH 10/11] revert 26c6e7844dedf5cea67b9233058f0875c7fc0dbd revert feat: Add remote-servers support for BIND 9.20 From dfa3f0d4c3921d6a9f745592d80bab23e3748af9 Mon Sep 17 00:00:00 2001 From: Daniel Akulenok Date: Fri, 23 Jan 2026 00:30:22 +0100 Subject: [PATCH 11/11] test: Configure Molecule testing framework - Add Ansible collections configuration - Update converge and prepare playbooks - Restructure molecule.yml for improved testing --- handlers/main.yml | 2 +- molecule/default/collections.yml | 7 +++++++ molecule/default/converge.yml | 6 ++++-- molecule/default/molecule.yml | 31 +++++++++++++++++-------------- molecule/default/prepare.yml | 6 ++++++ 5 files changed, 35 insertions(+), 17 deletions(-) create mode 100644 molecule/default/collections.yml create mode 100644 molecule/default/prepare.yml diff --git a/handlers/main.yml b/handlers/main.yml index f00c67b..f37a250 100644 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -18,7 +18,7 @@ - "{{ bind9_libdir }}" dest: "{{ bind9_backup_dir + '/bind9-config-' + - ansible_date_time.iso8601_basic_short + '.tar.gz' }}" + ansible_facts.date_time.iso8601_basic_short + '.tar.gz' }}" owner: root group: root mode: 0640 diff --git a/molecule/default/collections.yml b/molecule/default/collections.yml new file mode 100644 index 0000000..6f4772f --- /dev/null +++ b/molecule/default/collections.yml @@ -0,0 +1,7 @@ +--- +collections: + - name: ansible.utils + - name: ansible.posix + - name: community.crypto + - name: community.general + diff --git a/molecule/default/converge.yml b/molecule/default/converge.yml index ac3ff8c..d63642f 100644 --- a/molecule/default/converge.yml +++ b/molecule/default/converge.yml @@ -1,5 +1,7 @@ --- - name: Converge hosts: all - roles: - - keepit.bind9 + tasks: + - name: Include bind9 role + ansible.builtin.include_role: + name: ../../../ansible-bind9-role diff --git a/molecule/default/molecule.yml b/molecule/default/molecule.yml index 8ea2e57..c5ae4d5 100644 --- a/molecule/default/molecule.yml +++ b/molecule/default/molecule.yml @@ -1,22 +1,25 @@ --- -dependency: - name: galaxy driver: name: podman platforms: - - name: ubuntu-jammy - image: ubuntu:jammy - - name: ubuntu-focal - image: ubuntu:focal - - name: debian-bullseye - image: debian:bullseye + - name: debian-bookworm + image: docker.io/jrei/systemd-debian:12 + command: /lib/systemd/systemd + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host + - name: debian-trixie + image: docker.io/jrei/systemd-debian:13 + command: /lib/systemd/systemd + privileged: true + volumes: + - /sys/fs/cgroup:/sys/fs/cgroup:rw + cgroupns_mode: host provisioner: name: ansible - lint: - name: ansible-lint + config_options: + defaults: + ALLOW_BROKEN_CONDITIONALS: true verifier: name: ansible -lint: | - set -e - ansible-lint . - yamllint . diff --git a/molecule/default/prepare.yml b/molecule/default/prepare.yml new file mode 100644 index 0000000..b3823cd --- /dev/null +++ b/molecule/default/prepare.yml @@ -0,0 +1,6 @@ +--- +- hosts: all + tasks: + - name: Update apt + ansible.builtin.apt: + update_cache: true