---
- name: Install bind9 packages
  tags: bind9
  become: true
  ansible.builtin.apt:
    pkg: "{{ bind9_packages }}"
    state: present
    cache_valid_time: 600

- name: Set Bind to ipv4 only
  tags: bind9
  become: true
  ansible.builtin.replace:
   path: /etc/default/named
   regexp: '^OPTIONS=.*$'
   replace: 'OPTIONS="-u bind -4"'

- name: Setup logs
  tags: bind9
  become: true
  when: bind9_named_logging
  block:
    - name: Ensure existence of the log directory
      ansible.builtin.file:
        path: "{{ bind9_log_path }}"
        state: directory
        owner: "{{ bind9_user }}"
        group: "{{ bind9_group }}"
        mode: 0755

    - name: Configure log rotate for bind9
      ansible.builtin.template:
        src: "{{ bind9_templates | default('') }}logrotate.d/bind.j2"
        dest: /etc/logrotate.d/bind
        owner: root
        group: "{{ bind9_group }}"
        mode: 0644

- name: Create dynamic DNS keys
  tags: bind9
  ansible.builtin.include_tasks: create_ddns_keys.yml
  with_items:
    - "{{ bind9_zones_static + bind9_zones_dynamic }}"
  when: bind9_generate_ddns_key | bool

- name: Configure bind9 named.conf files
  tags: bind9
  become: true
  ansible.builtin.template:
    src: "{{ bind9_templates | default('') }}bind/{{ item }}.j2"
    dest: /etc/bind/{{ item }}
    owner: root
    group: "{{ bind9_group }}"
    mode: "0644"
  with_items:
    - named.conf.local
    - named.conf.options
  notify:
    - Reload bind9
  # Variable register for eventual use outside the role
  register: bind9_named_conf

- name: Check validity of named.conf
  tags: bind9
  ansible.builtin.command: named-checkconf
  register: bind9_reg_named_checkconf
  become: true
  become_user: "{{ bind9_user }}"
  changed_when: False
  vars:
    ansible_ssh_pipelining: True

- name: Create bind9 directory for master zones
  tags: bind9
  become: true
  ansible.builtin.file:
    path: "{{ bind9_zonedir }}"
    state: directory
    owner: root
    group: "{{ bind9_group }}"
    mode: "02775"
  when: bind9_authoritative | default()

- name: Create bind9 directory for master zone includes
  tags: bind9
  become: true
  ansible.builtin.file:
    path: "{{ bind9_zonedir }}/includes"
    state: directory
    owner: root
    group: "{{ bind9_group }}"
    mode: "0755"
  when: bind9_authoritative | default()

- name: Install bind9 authoritative include files
  tags: bind9
  become: true
  ansible.builtin.template:
    src: "bind/zones/includes/{{ item }}.j2"
    dest: "{{ bind9_zonedir }}/includes/{{ item }}"
    owner: root
    group: "{{ bind9_group }}"
    mode: "0644"
  with_items: "{{ bind9_authoritative_includes }}"
  when: bind9_authoritative | default()
  notify:
    - Zone file change
    - Reload bind9

#- name: Install bind9 rndc key
#  become: true
#  ansible.builtin.template:
#    src: "{{ bind9_templates | default('') }}bind/rndc.key.j2"
#    dest: /etc/bind/rndc.key
#    owner: "{{ bind9_user }}"
#    group: "{{ bind9_group }}"
#    mode: "0640"
#  when: bind9_rndc_key | default()
#  notify:
#    - Restart bind9
#  tags:
#    - role:bind9:rndc_key
#
#- name: Create bind9 directory for keys
#  become: true
#  ansible.builtin.file:
#    path: "{{ bind9_keydir }}"
#    state: directory
#    owner: "{{ bind9_user }}"
#    group: "{{ bind9_group }}"
#    mode: 02750
#  when: bind9_authoritative | default()
#  tags:
#    - role:bind9:ddns
#    - role:bind9:dnssec
#
## TODO: DDNS: move keys into vault file
#- name: Copy over DDNS keys for zones with update_keyfile
#  tags: bind9
#  become: true
#  ansible.builtin.copy:
#    src: bind/zones/{{ item.update_keyfile }}.key
#    dest: "{{ bind9_keydir }}/{{ item.update_keyfile }}.key"
#    owner: "{{ bind9_user }}"
#    group: "{{ bind9_group }}"
#    mode: "0644"
#  with_items:
#    - "{{ bind9_zones_static + bind9_zones_dynamic }}"
#  when:
#    - bind9_authoritative | default()
#    - item.type | default(bind9_zone_type) == 'master'
#    - item.update_keyfile | default()
#
#- name: Copy over DDNS private keys for zones with update_keyfile
#  tags: bind9
#  become: true
#  ansible.builtin.copy:
#    src: bind/zones/{{ item.update_keyfile }}.private
#    dest: "{{ bind9_keydir }}/{{ item.update_keyfile }}.private"
#    owner: "{{ bind9_user }}"
#    group: "{{ bind9_group }}"
#    mode: "0600"
#  with_items:
#    - "{{ bind9_zones_static + bind9_zones_dynamic }}"
#  when:
#    - bind9_authoritative | default()
#    - item.type | default(bind9_zone_type) == 'master'
#    - item.update_keyfile | default()
#
## TODO: DNSSEC: implement key rollover
#- name: Determine if DNSSEC keys for zones already exist
#  become: true
#  ansible.builtin.find:
#    paths: "{{ bind9_keydir }}"
#    patterns: "K{{ item.name }}.+008+*"
#  register: bind9_reg_dnssec_keys_tmp
#  with_items:
#    - "{{ bind9_zones_dynamic + bind9_zones_static }}"
#  when:
#    - bind9_authoritative | default()
#    - bind9_dnssec | default() or item.dnssec | default(bind9_dnssec_zones_default_enabled)
#    - item.dnssec | default(bind9_dnssec_zones_default_enabled)
#  tags:
#    - role:bind9:dnssec
#
## Filter out all skipped results (e.g. if item.dnssec is set to False)
#- name: Set bind9_reg_dnssec_keys
#  become: true
#  tags: bind9
#  ansible.builtin.set_fact:
#    bind9_reg_dnssec_keys: "{{ bind9_reg_dnssec_keys_tmp.results | selectattr('skipped', 'undefined') | list }}"
#
#- name: Generate bind9 key signing keys for zones
#  ansible.builtin.command: dnssec-keygen -a RSASHA256 -b 4096 -n ZONE -f KSK {{ item.item.name }}
#  args:
#    chdir: "{{ bind9_keydir }}"
#  register: bind9_reg_keygen_ksk
#  changed_when: bind9_reg_keygen_ksk.rc != 0
#  become: true
#  become_user: "{{ bind9_user }}"
#  with_items: "{{ bind9_reg_dnssec_keys }}"
#  when:
#    - bind9_authoritative | default()
#    - bind9_dnssec | default()
#    - item.matched < 2
#  notify:
#    - Reload bind9
#  tags:
#    - role:bind9:dnssec
#
#- name: Generate bind9 zone signing keys for zones
#  ansible.builtin.command: dnssec-keygen -a RSASHA256 -b 2048 -n ZONE {{ item.item.name }}
#  args:
#    chdir: "{{ bind9_keydir }}"
#  register: bind9_reg_keygen_zsk
#  changed_when: bind9_reg_keygen_zsk.rc != 0
#  become: true
#  become_user: "{{ bind9_user }}"
#  with_items: "{{ bind9_reg_dnssec_keys }}"
#  when:
#    - bind9_authoritative | default()
#    - bind9_dnssec | default()
#    - item.matched < 2
#  notify:
#    - Reload bind9
#  tags:
#    - role:bind9:dnssec
#
#- name: Read in key signing keys from key files (DNSKEY)
#  become: true
#  ansible.builtin.command: "grep 'IN DNSKEY' {{ bind9_keydir }}/{{ item.stdout }}.key"
#  register: bind9_reg_ksk
#  changed_when: false
#  with_items: "{{ bind9_reg_keygen_ksk.results }}"
#  when:
#    - bind9_authoritative | default()
#    - bind9_dnssec | default()
#    - item.changed | default()
#  tags:
#    - role:bind9:dnssec
#
#- name: Generate DS records from key signing keys
#  become: true
#  ansible.builtin.command: "dnssec-dsfromkey -2 {{ bind9_keydir }}/{{ item.stdout }}.key"
#  register: bind9_reg_ksk_ds
#  changed_when: false
#  with_items: "{{ bind9_reg_keygen_ksk.results }}"
#  when:
#    - bind9_authoritative | default()
#    - bind9_dnssec | default()
#    - item.changed | default()
#  tags:
#    - role:bind9:dnssec
#
#- name: Generate notification message
#  become: true
#  ansible.builtin.set_fact:
#    notification_message: |
#      New key signing key (KSK) for zone "{{ item.0.item.item.item.name }}" needs to be inserted/updated at registrar (use the format that the registrar demands):
#
#      {{ item.0.stdout }}
#
#      {{ item.1.stdout }}
#  with_together:
#    - "{{ bind9_reg_ksk.results }}"
#    - "{{ bind9_reg_ksk_ds.results }}"
#  when:
#    - bind9_authoritative
#    - bind9_dnssec | default()
#    - item.0.item.changed | default()
#    - bind9_dnssec_notify_xmpp or bind9_dnssec_notify_matrix
#  tags:
#    - role:bind9:dnssec
#
#- name: Send KSK in DNSSEC and DS format over XMPP
#  become: true
#  community.general.jabber:
#    user: "{{ bind9_dnssec_notify_xmpp_user }}"
#    password: "{{ bind9_dnssec_notify_xmpp_password }}"
#    to: "{{ bind9_dnssec_notify_xmpp_rcpt }}"
#    msg: "{{ notification_message }}"
#  delegate_to: "{{ bind9_dnssec_notify_xmpp_host }}"
#  ignore_errors: "{{ ansible_check_mode }}"
#  with_together:
#    - "{{ bind9_reg_ksk.results }}"
#    - "{{ bind9_reg_ksk_ds.results }}"
#  when:
#    - bind9_authoritative
#    - bind9_dnssec | default()
#    - item.0.item.changed | default()
#    - bind9_dnssec_notify_xmpp
#  tags:
#    - role:bind9:dnssec
#
## send message to matrix
#- name: Set matrix notification message
#  become: true
#  ansible.builtin.set_fact:
#    bind9_matrix_notifier_text: "{{ notification_message }}"
#  ignore_errors: "{{ ansible_check_mode }}"
#  with_together:
#    - "{{ bind9_reg_ksk.results }}"
#    - "{{ bind9_reg_ksk_ds.results }}"
#  when:
#    - bind9_authoritative
#    - bind9_dnssec | default()
#    - item.0.item.changed | default()
#    - bind9_dnssec_notify_matrix
#  tags:
#    - role:bind9:dnssec
#
#- name: Send message to matrix via webhook
#  become: true
#  ansible.builtin.uri:
#    url: "{{ bind9_matrix_notifier_url }}"
#    method: POST
#    body: "{{ bind9_matrix_notifier_body | to_nice_json }}"
#    status_code: 200
#    body_format: json
#  ignore_errors: "{{ ansible_check_mode }}"
#  with_together:
#    - "{{ bind9_reg_ksk.results }}"
#    - "{{ bind9_reg_ksk_ds.results }}"
#  when:
#    - bind9_authoritative
#    - bind9_dnssec | default()
#    - item.0.item.changed | default()
#    - bind9_dnssec_notify_matrix
#  tags:
#    - role:bind9:dnssec

- name: Create dynamic bind9 zone files
  become: true
  ansible.builtin.template:
    src: "{{ bind9_templates | default('') }}bind/zones/db.template.j2"
    dest: "{{ bind9_zonedir }}/db.{{ item.name }}"
    owner: root
    group: "{{ bind9_group }}"
    mode: "0644"
  with_items: "{{ bind9_zones_dynamic }}"
  when:
    - bind9_authoritative | default()
    - item.type | default(bind9_zone_type) == 'master'
  notify:
    - Zone file change
    - Reload bind9
  tags:
    - role:bind9:zones
    - bind9
    - bind9-zones

- name: Install static bind9 zone files
  become: true
  # with src: "{{ inventory_hostname }}/bind/zones/db.{{ item.name }}"
  # Could not find or access 'perfact-login-localdev/bind/zones/db.perfact.de' Searched in:
  #  roles/general/bind9/files/perfact-login-localdev/bind/zones/db.perfact.de
  #  roles/general/bind9/perfact-login-localdev/bind/zones/db.perfact.de
  #  roles/general/bind9/tasks/files/perfact-login-localdev/bind/zones/db.perfact.de
  #  roles/general/bind9/tasks/perfact-login-localdev/bind/zones/db.perfact.de
  # ==>> files/perfact-login-localdev/bind/zones/db.perfact.de  <==
  #  perfact-login-localdev/bind/zones/db.perfact.de
  #
  ansible.builtin.template:
    src: "{{ inventory_hostname }}/bind/zones/db.{{ item.name }}.j2"
    dest: "{{ bind9_zonedir }}/db.{{ item.name }}"
    owner: root
    group: "{{ bind9_group }}"
    mode: "0644"
    force: "{{ item.force_update | default('yes') }}"
  with_items: "{{ bind9_zones_static }}"
  when:
    - bind9_authoritative | default()
    - item.type | default(bind9_zone_type) == 'master'
  notify:
    - Zone file change
    - Reload bind9
  tags:
    - role:bind9:zones
    - bind9
    - bind9-zones

- name: Check validity of zone files
  tags:
    - role:bind9:zones
    - bind9
    - bind9-zones
  ansible.builtin.command: named-checkzone {{ item.name }} {{ bind9_zonedir }}/db.{{ item.name }}
  register: bind9_reg_named_checkzone
  become: true
  become_user: "{{ bind9_user }}"
  with_items:
    - "{{ bind9_zones_dynamic }}"
    - "{{ bind9_zones_static }}"
  when: item.type | default(bind9_zone_type) == 'master'
  changed_when: False
  vars:
    ansible_ssh_pipelining: True


- name: Import monit tasks
  tags: bind9
  become: true
  ansible.builtin.import_tasks: monit.yml
  when: bind9_monit_enabled | default()
