# SPDX-License-Identifier: MIT
---

# To run this test, AD (ad1) needs to be present in the inventory
# AD should be pre-configured as a dns for the client machine.
# AD's DNS service should be configured with both forward and reverse zones
# and the DNS records from any previous runs removed.
# Note that both for client and ad the ansible_host should
# contain the ip4 address to make this work properly.
# There is expectation that both client and ad are on the
# same network with mask 255.255.255.0.

# Example inventory:
# [client]
# client1 ansible_host=<CLIENT IP>\
#  ad_integration_password=Secret123 ad_integration_realm="domain.com" \
#  ad_dyndns_update=true
# [ad]
# ad1 ansible_host=<AD IP> ansible_connection=winrm\
#  ansible_password=Secret123 ansible_port=5986 ansible_user=Administrator\
#  ansible_winrm_server_cert_validation=ignore

- name: Set variables
  hosts: client
  tasks:
    - name: Set ad_integration_realm if it is not defined or is empty
      set_fact:
        ad_integration_realm: domain.com
      when: ad_integration_realm is not defined or not ad_integration_realm

- name: Configure DynDNS on AD
  hosts: ad
  gather_facts: true
  tasks:
    - name: Get AD address
      set_fact:
        ad_address: "{{ hostvars[inventory_hostname].ansible_host }}"
    - name: Get network for zone
      set_fact:
        network_ad: >-
          {{ ad_address.split('.')[-2::-1] | join('.') }}.in-addr.arpa
    - name: Show AD network
      debug:
        msg: "AD network: {{ network_ad }}"
    - name: Create reverse zone
      ansible.windows.win_command: >-
        dnscmd.exe /zoneadd {{ network_ad }} /primary
      register: res
      failed_when:
        - res.rc != 0 and "DNS_ERROR_ZONE_ALREADY_EXISTS" not in res.stdout
    - name: Allow updates in the zone
      ansible.windows.win_command: >-
        dnscmd.exe /config
        {{ hostvars[groups['client'][0]].ad_integration_realm }}
        /allowupdate 1
    - name: Allow updates in the reverse zone
      ansible.windows.win_command: >-
        dnscmd.exe /config {{ network_ad }} /allowupdate 1
    - name: Disable dns forwarders
      # noqa: fqcn[action]
      win_command: dnscmd.exe /config /norecursion 1

- name: Ensure that the role configures dynamic dns
  hosts: client
  gather_facts: true
  tasks:
    - name: Run the integration
      when: "'ad' in groups and groups['ad']"
      block:
        - name: Debug dyndns settings
          debug:
            msg: >-
              Interface {{ _ad_dyndns_iface | default(ansible_default_ipv4.interface) }} and server
              : {{ hostvars[groups['ad'][0]].ansible_host }}
        - name: Run the system role with proper config
          include_role:
            name: linux-system-roles.ad_integration
            public: true
          vars:
            ad_dyndns_server: "{{ hostvars[groups['ad'][0]].ansible_host }}"
            ad_dyndns_iface: "{{ _ad_dyndns_iface | default(ansible_default_ipv4.interface) }}"
            ad_dyndns_auth: "none"
            ad_dyndns_update: true
            ad_dyndns_refresh_interval: 60
            ad_integration_sssd_custom_settings:
              - key: debug_level
                value: 9
        - name: Clean sssd log
          command: >-
            truncate -s 0  /var/log/sssd/sssd_{{ ad_integration_realm }}.log
          changed_when: true
          failed_when: false
        - name: Restart sssd
          service:
            name: sssd
            state: restarted
        - name: Pause for 5 to give sssd chance to refresh dn record on AD
          ansible.builtin.pause:
            minutes: 5
        - name: Check sssd log for dydndns update info
          command: >-
            grep -A 20 "nsupdate"
            /var/log/sssd/sssd_{{ ad_integration_realm }}.log
          changed_when: false
          failed_when: false
        - name: Grab sssd.conf contents
          command: cat {{ __ad_integration_sssd_conf | quote }}
          changed_when: false
        - name: Get IP for host's FQDN
          command: >-
            dig +short {{ ansible_fqdn }}.{{
            hostvars[groups['client'][0]].ad_integration_realm }} A
          register: dig_hostname
          changed_when: false
          failed_when: false
        - name: Get hostname for host's IP address
          command: "dig +short -x {{ ansible_default_ipv4.address }} PTR"
          register: dig_ip
          changed_when: false
          failed_when: false
        - name: Print to console dig outputs
          debug:
            msg:
              - "Dig hostname: {{ dig_hostname.stdout }}"
              - "Dig ip: {{ dig_ip.stdout }}"

- name: Check hosts on AD
  hosts: ad
  gather_facts: true
  tasks:
    - name: Get network for zone
      set_fact:
        network_ad: >-
          {{ ad_address.split('.')[-2::-1] | join('.') }}.in-addr.arpa
        client_ip_part: >-
          {{ hostvars[groups['client'][0]].ansible_host.split('.')[-1] }}
    - name: Show network information
      debug:
        msg: >-
          AD network: {{ network_ad }}, Client IP:
          {{ hostvars[groups['client'][0]].ansible_host }}
    - name: List all AD zones
      # noqa: fqcn[action]
      win_command: dnscmd.exe /EnumZones
      register: zones
      failed_when: false
    - name: Grab AD zone
      # noqa: command-instead-of-shell
      ansible.windows.win_shell: >-
        dnscmd.exe /zoneprint
        {{ hostvars[groups["client"][0]].ad_integration_realm }} |
        findstr /c:"client"
      register: zone_ad
      failed_when: false
    - name: Grab AD reverse zone
      # noqa: command-instead-of-shell
      ansible.windows.win_shell: >-
        dnscmd.exe /zoneprint {{ network_ad }} | findstr /c:"client"
      register: reverse_zone_ad
      failed_when: false
    - name: Show AD zones
      debug:
        msg:
          - "Zones:"
          - "{{ zones }}"
          - "Zone:"
          - "{{ zone_ad }}"
          - "Reverse zone:"
          - "{{ reverse_zone_ad }}"
    - name: Test - client is in AD both in forward and reverse zones
      assert:
        that:
          - hostvars[groups["client"][0]].ansible_host in zone_ad.stdout
          - client_ip_part in reverse_zone_ad.stdout

- name: Leave realm
  hosts: client
  tasks:
    - name: Teardown - Leave realm
      command: realm leave
      ignore_errors: true  # noqa ignore-errors
      changed_when: false
