---
# yamllint disable rule:line-length
- name: Test mesh tunnels with certificates
  hosts: all
  vars_files:
    - './vars/main.yml'
  vars:
    __vpn_num_hosts: 2
    __vpn_main_certname: "main_cert"
  # see RFC 5737, the following CIDRs are provided for documentation/testing use
    __vpn_private_host_cidr: "203.0.113.0/24"
    __vpn_clear_host_cidr: "198.51.100.0/24"
  # test to set true to manage firewall only
    vpn_manage_firewall: true
  tasks:
    - name: Set up test environment
      vars:
        __vpn_opportunistic: true
      include_tasks: tasks/setup_test.yml

    - name: Add extra options to check
      set_fact:
        __new_vpn_connections: "{{ __new_vpn_connections | d([]) + [item | combine(new_tunnel)] | list }}"
      loop: "{{ vpn_connections }}"
      vars:
        new_tunnel:
          policies:
            - policy: private
              cidr: "{{ __vpn_private_host_cidr }}"
            - policy: clear
              cidr: "{{ __vpn_clear_host_cidr }}"
          auth_method: cert
          opportunistic: true

    - name: Reset vpn_connections
      set_fact:
        vpn_connections: "{{ __new_vpn_connections }}"

    - name: Add cert_name fact to controller
      set_fact:
        cert_name: "{{ __vpn_main_certname }}"

    - name: Use vpn role
      include_role:
        name: fedora.linux_system_roles.vpn
        public: true
      ignore_errors: true # noqa ignore-errors

    - name: Flush handlers
      meta: flush_handlers

    - name: Assert file existence
      include_tasks: tasks/assert_mesh_conf_exists.yml

    - name: Reset success flag
      set_fact:
        __vpn_success: true

    - name: Get and store mesh.conf file
      slurp:
        src: "/etc/ipsec.d/mesh.conf"
      register: __vpn_register_conf

    - name: Extract content for conn private
      set_fact:
        conn_private: "{{ __vpn_register_conf['content'] | b64decode | regex_findall('^conn\\sprivate\\n[\\s\\S]*?(?=\\n\\n)', multiline=true) | first }}"

    - name: Extract content for conn private-or-clear
      set_fact:
        conn_private_or_clear: "{{ __vpn_register_conf['content'] | b64decode | regex_findall('^conn\\sprivate-or-clear\\n[\\s\\S]*?(?=\\n\\n)', multiline=true) | first }}"

    - name: Extract content for conn clear
      set_fact:
        conn_clear: "{{ __vpn_register_conf['content'] | b64decode | regex_findall('^conn\\sclear\\n[\\s\\S]*', multiline=true) | first }}"

    - name: Check that private section contains correct information
      set_fact:
        __vpn_success: false
      when: >-
        conn_private is not search('type=tunnel') or
        conn_private is not search('left=%defaultroute') or
        conn_private is not search('leftid=%fromcert') or
        conn_private is not search('rightid=%fromcert') or
        conn_private is not search('rightrsasigkey=%cert') or
        conn_private is not search('rightca=%same') or
        conn_private is not search('leftcert=' + __vpn_main_certname) or
        conn_private is not search('auto=route') or
        conn_private is not search('right=%opportunisticgroup') or
        conn_private is not search('negotiationshunt=hold') or
        conn_private is not search('failureshunt=drop') or
        conn_private is not search('ikev2=insist') or
        conn_private is not search('keyingtries=1') or
        conn_private is not search('retransmit-timeout=2s')

    - name: Assert success for private part of conf file
      assert:
        that: __vpn_success | d(false)
        msg: Found errors in conn private section of mesh.conf file

    - name: Check that private-or-clear section contains correct information
      set_fact:
        __vpn_success: false
      when: >-
        conn_private_or_clear is not search('type=tunnel') or
        conn_private_or_clear is not search('left=%defaultroute') or
        conn_private_or_clear is not search('leftid=%fromcert') or
        conn_private_or_clear is not search('rightid=%fromcert') or
        conn_private_or_clear is not search('rightrsasigkey=%cert') or
        conn_private_or_clear is not search('rightca=%same') or
        conn_private_or_clear is not search('leftcert=' + __vpn_main_certname) or
        conn_private_or_clear is not search('auto=route') or
        conn_private_or_clear is not search('right=%opportunisticgroup') or
        conn_private_or_clear is not search('negotiationshunt=hold') or
        conn_private_or_clear is not search('failureshunt=passthrough') or
        conn_private_or_clear is not search('ikev2=insist') or
        conn_private_or_clear is not search('keyingtries=1') or
        conn_private_or_clear is not search('retransmit-timeout=2s')

    - name: Assert success for private or clear part of conf file
      assert:
        that: __vpn_success | d(false)
        msg: Found errors in conn private-or-clear section of mesh.conf file

    - name: Check that clear section contains correct information
      set_fact:
        __vpn_success: false
      when: >-
        conn_clear is not search('type=passthrough') or
        conn_clear is not search('left=%defaultroute') or
        conn_clear is not search('right=%group') or
        conn_clear is not search('auto=route') or
        conn_clear is not search('authby=never')

    - name: Assert success for clear part of conf file
      assert:
        that: __vpn_success | d(false)
        msg: Found errors in conn clear section of mesh.conf file

    - name: Get and store policies private file
      slurp:
        src: "/etc/ipsec.d/policies/private"
      register: __vpn_register_private

    - name: Get and store policies private or clear file
      slurp:
        src: "/etc/ipsec.d/policies/private-or-clear"
      register: __vpn_register_private_or_clear

    - name: Get and store policies clear file
      slurp:
        src: "/etc/ipsec.d/policies/clear"
      register: __vpn_register_clear

    - name: Check contents of policy private file
      set_fact:
        __vpn_success: false
      when: >-
        __vpn_register_private['content'] | b64decode
        is not search(__vpn_private_host_cidr)

    - name: Assert success for policy private file
      assert:
        that: __vpn_success | d(false)
        msg: Found errors policies/private file

    - name: Check contents of policy private or clear file
      set_fact:
        __vpn_success: false
      when: >-
        __vpn_register_private_or_clear['content'] | b64decode
        is not search(__vpn_current_subnet) or
        __vpn_register_private_or_clear['content'] | b64decode
        is not search(__vpn_dynamic_hosts_sample_cidr)

    - name: Assert success for policy private or clear file
      assert:
        that: __vpn_success | d(false)
        msg: Found errors policies/private-or-clear file

    - name: Check contents of policy clear file
      set_fact:
        __vpn_success: false
      when: >-
        __vpn_register_clear['content'] | b64decode
        is not search(__vpn_clear_host_cidr)

    - name: Assert success for policy clear file
      assert:
        that: __vpn_success | d(false)
        msg: Found errors policies/clear file

    - name: Check the firewall and the selinux port status
      include_tasks: tasks/check_firewall_selinux.yml

    - name: Check for ansible_managed, fingerprint in generated files
      include_tasks: tasks/check_header.yml
      loop:
        - "{{ __vpn_register_conf }}"
        - "{{ __vpn_register_private }}"
        - "{{ __vpn_register_private_or_clear }}"
        - "{{ __vpn_register_clear }}"
      loop_control:
        loop_var: __file_content
      vars:
        __fingerprint: "system_role:vpn"

    - name: Cleanup
      include_tasks: tasks/cleanup.yml
      tags:
        - tests::cleanup
