- name: check if record is an object fail: msg: record must be an object when: record is not mapping - name: check if record zone is a string fail: msg: record zone must be a string when: record.zone is defined and record.zone is not string - name: check if record zone exists fail: msg: '"{{ record.zone }}" does not seem to be a valid zone' when: (record.zone is defined) and (record.zone != 'root') and ((int_zones is not defined) or (record.zone not in int_zones)) - name: construct record parameters set_fact: ns_zone: "{%- if (record.zone is defined) and (record.zone != 'root') -%}{{ record.zone }}\ {%- else -%}{{ ns_tld | d(int_tld) }}\ {%- endif -%}" ns_name: "{%- if record.name is defined -%}{{ record.name }}\ {%- else -%}{{ inventory_hostname }}\ {%- endif -%}" ns_type: "{%- if record.type is defined -%}{{ record.type | upper }}\ {%- else -%}A\ {%- endif -%}" ns_value: "{%- if record.value is defined -%}{{ record.value }}\ {%- else -%}{{ ansible_host }}\ {%- endif -%}" - name: set ns_quote set_fact: ns_quote: "{{ '\"' if ns_type == 'TXT' else '' }}" - name: construct full name set_fact: ns_full_name: '{%- if ns_name != "@" -%}{{ ns_name }}.{%- endif -%}{{ ns_zone }}' - name: construct regex part set_fact: ns_regex_part: '{%- if record.allow_multiple is defined -%}{{ (ns_quote ~ ns_value ~ ns_quote) | regex_escape() }}\.?{%- else -%}{{ "" | string }}{%- endif -%}' - name: construct regex set_fact: ns_regex: '^{{ ns_full_name | regex_escape() }}\s+\d+\s+IN\s+{{ ns_type | regex_escape() }}\s+{{ ns_regex_part }}' - name: show debug info debug: msg: "{{ ns_zone }} {{ ns_name }} {{ ns_type }} {{ ns_quote ~ ns_value ~ ns_quote }} --> {{ ns_regex }}" - name: slurp zone file slurp: src: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" register: zf changed_when: false - name: enumerate stdout lines to check if an entry already exists set_fact: ns_exists: "{{ (zf.content | b64decode).split('\n') | select('search', ns_regex) | list | length > 0 }}" - block: - name: fail if there are multiple records fail: msg: single record mode is selected, but multiple records found when: (zf.content | b64decode).split('\n') | select('search', ns_regex) | list | length > 1 - name: grab the value set_fact: ns_old_value: "{{ (zf.content | b64decode).split('\n') | select('search', ns_regex) | map('regex_search', '\\s+?(\\S+?)\\.?$', '\\1') | first | join('') }}" - name: replace the record lineinfile: path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" regexp: '^\s*{{ ns_name | regex_escape() }}\s+IN\s+{{ ns_type | regex_escape() }}\s+' line: "{{ ns_name }}\tIN\t{{ ns_type }}\t{{ ns_quote ~ ns_value ~ ns_quote }}" backrefs: yes when: ns_old_value != (ns_quote ~ ns_value ~ ns_quote) register: rr1 when: ns_exists and rrset.allow_multiple is not defined - name: add the record if it is missing lineinfile: path: "{{ coredns_conf_dir ~ '/' ~ (ns_tld | d(int_tld)) ~ '.zone' }}" line: "{{ ns_name }}\tIN\t{{ ns_type }}\t{{ ns_quote ~ ns_value ~ ns_quote }}" when: not ns_exists register: rr2 - name: determine if records were changed set_fact: ns_records_changed: "{{ ((rr1 is defined) and rr1.changed) or ((rr2 is defined) and rr2.changed) }}" - name: change serial include_tasks: increase_serial.yml when: ns_records_changed | d(false) == true - name: restart coredns service: name: coredns state: restarted when: (ns_instant | d(false) == true) and (ns_records_changed or ns_serial_changed)