Update CHANGELOG for v1.3.4 release; add new features and bug fixes
Some checks failed
Test Collection / Sanity Tests (Ansible devel) (push) Failing after 12s
Test Collection / Sanity Tests (Ansible stable-2.15) (push) Failing after 28s
Test Collection / Sanity Tests (Ansible stable-2.16) (push) Failing after 27s
Test Collection / Sanity Tests (Ansible stable-2.17) (push) Failing after 28s
Test Collection / Python Syntax Check (push) Failing after 6s
Test Collection / Build Collection (push) Failing after 10s
Test Collection / YAML and Ansible Lint (push) Successful in 10s
Test Collection / Documentation Check (push) Successful in 7s
Test Collection / Unit Tests (push) Successful in 8s

Add example playbooks for filtering and updating DNS zones
Enhance nsupdate_zone module with default_ttl handling and improved diff output
This commit is contained in:
Daniel Akulenok
2026-01-29 22:28:35 +01:00
parent c46a17748a
commit 212e2c42a8
7 changed files with 227 additions and 6 deletions

View File

@@ -4,6 +4,29 @@ Valid.Nsupdate_zone Collection Release Notes
.. contents:: Topics
v1.3.4
======
Release Summary
---------------
Enhancements to record handling, diff output, and defaults.
New Features
------------
- Add default_ttl parameter to apply a consistent TTL when records omit ttl
- Extend ignore_dnssec_records to ignore CDNSKEY, CDS, and TYPE65534
- Improve diff output to zone file format with +/- markers and per-record lines
Bugfixes
--------
- Allow extra keys in zones and records by filtering input before processing
- Fix diff output newline rendering by returning lists of lines
- Use correct Ansible diff flag via module._diff
- Improve error reporting with better messages and verbose traceback output
v1.3.3
======
@@ -18,6 +41,12 @@ New Features
- Add ignore_ns_records flag (default: true) to automatically ignore NS records
- Add support for extra keys in zones and records parameters via options_ignore_list
New Features
------------
- Add ignore_ns_records flag (default: true) to automatically ignore NS records
- Add support for extra keys in zones and records parameters via options_ignore_list
v1.3.2
======

View File

@@ -0,0 +1,76 @@
---
# Simpler approach: Just extract the fields you need inline
# This is cleaner and easier to understand/maintain
- name: Clean zones and update DNS
hosts: localhost
gather_facts: false
vars:
zones_with_extras:
- name: example.com
type: internal
comment: "Main domain"
dns_server: ns1.example.com
records:
- record: 'example.com.'
type: A
value: 192.168.1.1
ttl: 3600
comment: "Zone apex"
- record: www
type: A
value: 192.168.1.10
comment: "Web server"
ttl: 300
tasks:
- name: Extract cleaned zones with only valid keys
set_fact:
cleaned_zones: |
{% set zones = [] %}
{% for zone in zones_with_extras %}
{% set cleaned_zone = {
'name': zone.name,
'records': []
} %}
{% if zone.get('dns_server') %}
{% set _ = cleaned_zone.update({'dns_server': zone.dns_server}) %}
{% endif %}
{% for record in zone.records %}
{% set cleaned_record = {
'record': record.record,
'type': record.type,
'value': record.value
} %}
{% if record.get('ttl') %}
{% set _ = cleaned_record.update({'ttl': record.ttl}) %}
{% endif %}
{% if record.get('state') %}
{% set _ = cleaned_record.update({'state': record.state}) %}
{% endif %}
{% set _ = cleaned_zone.records.append(cleaned_record) %}
{% endfor %}
{% set _ = zones.append(cleaned_zone) %}
{% endfor %}
{{ zones }}
- name: Display cleaned zones
debug:
var: cleaned_zones
- name: Update DNS zones (no validation errors expected)
valid.nsupdate_zone.nsupdate_zone:
key_name: "nsupdate"
key_secret: "{{ vault_dns_key }}"
zones: "{{ cleaned_zones }}"
register: dns_result
# Uncomment when testing:
# check_mode: yes
- name: Show results
debug:
var: dns_result.results

110
examples/filter_zones.yml Normal file
View File

@@ -0,0 +1,110 @@
---
# Example playbook to filter zones variable to only include valid keys
# This is useful if you have extra metadata/comments in your zones definition
# and want to clean it before passing to nsupdate_zone module
- name: Filter and rebuild zones list with valid keys only
hosts: localhost
gather_facts: false
vars:
# Example zones with extra keys (comment, type, custom_field, etc.)
zones_with_extras:
- name: example.com
type: internal # <- extra key
comment: "Main domain" # <- extra key
custom_field: foo # <- extra key
dns_server: ns1.example.com
records:
- record: 'example.com.'
type: A
value: 192.168.1.1
ttl: 3600
comment: "Zone apex" # <- extra key
- record: www
type: A
value: 192.168.1.10
comment: "Web server" # <- extra key
ttl: 300
- name: example.org
type: external # <- extra key
dns_server: ns2.example.org
records:
- record: 'example.org.'
type: A
value: 192.168.2.1
ttl: 3600
tasks:
- name: Display original zones (with extra keys)
debug:
var: zones_with_extras
- name: Filter zones to valid keys only
set_fact:
cleaned_zones: "{{ zones_with_extras | map('dict2items') | map('selectattr', 'key', 'in', zone_valid_keys) | map('list') | map('items2dict') | list }}"
vars:
zone_valid_keys:
- name
- dns_server
- records
- name: Filter records within each zone to valid keys only
set_fact:
cleaned_zones: |
[
{%- for zone in cleaned_zones -%}
{
"name": {{ zone.name | to_json }},
{%- if zone.get('dns_server') %}
"dns_server": {{ zone.dns_server | to_json }},
{%- endif %}
"records": [
{%- for record in zone.records -%}
{
"record": {{ record.record | to_json }},
"type": {{ record.type | to_json }},
"value": {{ record.value | to_json }}
{%- if record.get('ttl') %},
"ttl": {{ record.ttl | to_json }}
{%- endif %}
{%- if record.get('state') %},
"state": {{ record.state | to_json }}
{%- endif %}
}{{ "," if not loop.last }}
{%- endfor %}
]
}{{ "," if not loop.last }}
{%- endfor %}
]
- name: Parse cleaned zones JSON
set_fact:
cleaned_zones: "{{ cleaned_zones | from_json }}"
- name: Display cleaned zones (only valid keys)
debug:
var: cleaned_zones
- name: Show the difference
debug:
msg: |
Original zone 0 keys: {{ zones_with_extras[0].keys() | list }}
Cleaned zone 0 keys: {{ cleaned_zones[0].keys() | list }}
Original record 0 keys: {{ zones_with_extras[0].records[0].keys() | list }}
Cleaned record 0 keys: {{ cleaned_zones[0].records[0].keys() | list }}
- name: Now you can use cleaned_zones with nsupdate_zone module
debug:
msg: |
The 'cleaned_zones' variable now contains only valid keys and can be passed
directly to the nsupdate_zone module without parameter validation errors:
- name: Update DNS zones
valid.nsupdate_zone.nsupdate_zone:
key_name: "nsupdate"
key_secret: "your-key"
zones: "{{ cleaned_zones }}"

View File

@@ -3,7 +3,7 @@
namespace: "valid"
name: "nsupdate_zone"
version: 1.3.3
version: 1.3.4
readme: README.md
authors:
- Dan Kercher

View File

@@ -389,6 +389,12 @@ class DNSZoneManager:
self.soa_minimum_ttl = 3600 # Default, will be updated from SOA
self.default_ttl = module.params.get('default_ttl') # User-specified default, or None to use SOA minimum
def _get_default_ttl(self) -> int:
"""Get the effective default TTL, preferring user-specified over SOA minimum."""
if self.default_ttl is not None:
return self.default_ttl
return self.soa_minimum_ttl
def _resolve_server(self) -> list[str]:
"""Resolve DNS server FQDN to IP addresses."""
server = self.dns_server
@@ -506,7 +512,7 @@ class DNSZoneManager:
record_name = record_config['record']
record_type = record_config['type'].upper()
record_values = record_config['value']
record_ttl = record_config.get('ttl', self.soa_minimum_ttl)
record_ttl = record_config.get('ttl', self._get_default_ttl())
record_state = record_config.get('state', 'present')
# Normalize record name
@@ -880,7 +886,7 @@ class DNSZoneManager:
for record in sorted(changes['deletes'], key=lambda r: (r['name'].to_text(), r['type'])):
record_name = record['name'].to_text().rstrip('.')
record_type = record['type']
ttl = record.get('ttl', self.soa_minimum_ttl)
ttl = record.get(\'ttl\', self._get_default_ttl())
values = sorted(str(v) for v in record['values'])
for value in values:
before_lines.append(f"-{record_name:<34} {ttl:<10} {record_type:<10} {value}")
@@ -889,7 +895,7 @@ class DNSZoneManager:
for record in sorted(changes['adds'], key=lambda r: (r['name'].to_text(), r['type'])):
record_name = record['name'].to_text().rstrip('.')
record_type = record['type']
ttl = record.get('ttl', self.soa_minimum_ttl)
ttl = record.get(\'ttl\', self._get_default_ttl())
values = sorted(str(v) for v in record['values'])
for value in values:
after_lines.append(f"+{record_name:<34} {ttl:<10} {record_type:<10} {value}")
@@ -898,8 +904,8 @@ class DNSZoneManager:
for record in sorted(changes['updates'], key=lambda r: (r['name'].to_text(), r['type'])):
record_name = record['name'].to_text().rstrip('.')
record_type = record['type']
old_ttl = record.get('old_ttl', self.soa_minimum_ttl)
new_ttl = record.get('new_ttl', self.soa_minimum_ttl)
old_ttl = record.get(\'old_ttl\', self._get_default_ttl())
new_ttl = record.get(\'new_ttl\', self._get_default_ttl())
old_values = sorted(str(v) for v in record['old_values'])
new_values = sorted(str(v) for v in record['new_values'])

Binary file not shown.

Binary file not shown.