notify: reload named
when: item.value.dynamic == true
-# This makes sure dynamic DNS records in the journal files are in sync with the
-# actual zone files so we can store them in the next step.
-- name: Sync Dynamic DNS journals with zone files
- command: "rndc sync -clean {{ item.key }}"
- with_dict: "{{ named_domains }}"
- when: item.value.dynamic == true and
- item.value.ddns_hostname_prefixes is defined
- # Don't fail if there is no journal file
- failed_when: false
-
-- name: Create temporary directory for dynamic A records
+# We store new zone files in a temp directory because it takes ansible minutes
+# to write all the files. If we prevented DDNS updates while they were
+# getting written, there's a good chance some updates would get refused.
+# We copy these to named_conf_zones_path at the end.
+- name: Create temporary directory for zone files
command: "mktemp -d"
register: named_tempdir
-# We need to store existing DNS records in a temp file so we can spit
-# them back out into the zone file after static records are written.
-# Given hostname prefix(es) to expect, this task greps for those records
-# and stores them in a temporary file named after the domain.
-- name: Store existing dynamic A records
- shell: "grep -E '^({% for prefix in item.value.ddns_hostname_prefixes %}{{ prefix }}{% if not loop.last %}|{% endif %}{% endfor %})[0-9]+\\s+A' {{ named_conf_zones_path }}/{{ item.key }} > {{ named_tempdir.stdout }}/{{ item.key }}"
- with_dict: "{{ named_domains }}"
- when: item.value.dynamic == true and
- item.value.ddns_hostname_prefixes is defined
- # Don't fail if there are no records to store
- failed_when: false
-
-- name: Write forward zone files
+- name: Write forward zone files to tempdir
template:
src: forward.j2
- dest: "{{ named_conf_zones_path }}/{{ item.key }}"
+ dest: "{{ named_tempdir.stdout }}/{{ item.key }}"
validate: named-checkzone {{ item.key }} %s
with_dict: "{{ named_domains }}"
notify: reload named
when: (item.value.dynamic != true) or
(item.value.dynamic == true and item.value.ddns_hostname_prefixes is defined)
-- name: Write reverse zone files
+- name: Write reverse zone files to tempdir
template:
src: reverse.j2
- dest: "{{ named_conf_zones_path }}/{{ item.1 }}"
+ dest: "{{ named_tempdir.stdout }}/{{ item.1 }}"
validate: named-checkzone {{ item.1 }} %s
with_subelements:
- "{{ named_domains }}"
skip_missing: True
notify: reload named
-- name: Restore dynamic A records from temp file(s)
- shell: "cat {{ named_tempdir.stdout }}/{{ item.key }} >> {{ named_conf_zones_path }}/{{ item.key }}"
+# This makes sure dynamic DNS records in the journal files are in sync with the
+# actual zone files so we can store them in the next 2 steps.
+- name: Sync Dynamic DNS journals with zone files
+ command: "rndc sync -clean {{ item.key }}"
with_dict: "{{ named_domains }}"
when: item.value.dynamic == true and
item.value.ddns_hostname_prefixes is defined
- # Don't fail if there are no records to restore
+ # Don't fail if there is no journal file
failed_when: false
-# This gets rid of any cached dynamic records that we didn't just restore
-- name: Freeze, reload, thaw dynamic zone files
- shell: "rndc freeze; rndc reload; rndc thaw"
+# Prevents dynamic DNS record updates so we can capture current DDNS records
+# and move our new zone files into place without them getting overwritten.
+- name: Freeze Dynamic DNS zones to prevent updates
+ command: "rndc freeze {{ item.key }}"
+ with_dict: "{{ named_domains }}"
+ when: item.value.dynamic == true and
+ item.value.ddns_hostname_prefixes is defined
+
+- name: Spit existing dynamic A records into new/temp forward zone file
+ shell: "grep -E '^({% for prefix in item.value.ddns_hostname_prefixes %}{{ prefix }}{% if not loop.last %}|{% endif %}{% endfor %})[0-9]+\\s+A' {{ named_conf_zones_path }}/{{ item.key }} >> {{ named_tempdir.stdout }}/{{ item.key }}"
+ with_dict: "{{ named_domains }}"
+ when: item.value.dynamic == true and
+ item.value.ddns_hostname_prefixes is defined
+ # Don't fail if there are no records to store
+ failed_when: false
+
+- name: Move all new/temp zone files to actual zone file dir
+ shell: "mv -vf {{ named_tempdir.stdout }}/* {{ named_conf_zones_path }}/"
+
+# Re-run setup module to update ansible_date_time.epoch
+- name:
+ setup:
+
+- name: Set new_named_serial variable
+ set_fact:
+ new_named_serial: "{{ ansible_date_time.epoch }}"
+
+# Since ansible takes a while to write the new/temp zone files, it is likely
+# a DDNS record update incremented the serial so the original named_serial is
+# too old. We replace it here to be safe.
+- name: Overwrite zone file serial number
+ shell: "sed -i 's/{{ named_serial }}/{{ new_named_serial }}/g' {{ named_conf_zones_path }}/*"
+
+# Context is incorrect due to the files being written to a temp directory first
+- name: Restore SELinux context on zone files
+ command: "restorecon -r {{ named_conf_zones_path }}"
+
+# This re-enables dynamic DNS record updates
+- name: Thaw frozen zone files
+ shell: "rndc thaw {{ item.key }}"
+ with_dict: "{{ named_domains }}"
+ when: item.value.dynamic == true and
+ item.value.ddns_hostname_prefixes is defined
-- name: Clean up dynamic A records temp dir
+- name: Clean up temp dir
file:
path: "{{ named_tempdir.stdout }}"
state: absent