---
# Copyright (c) Ansible Project
# GNU General Public License v3.0+ (see LICENSES/GPL-3.0-or-later.txt or https://www.gnu.org/licenses/gpl-3.0.txt)
# SPDX-License-Identifier: GPL-3.0-or-later

- name: "create a blocking ruleset with a DROP policy"
  copy:
    dest: "{{ iptables_tests }}"
    content: |
      *filter
      :INPUT DROP
      COMMIT



- name: "restore state from the test file (check_mode, must report a change)"
  iptables_state:
    path: "{{ iptables_tests }}"
    state: restored
  register: iptables_state
  check_mode: yes

- name: "assert that results are as expected"
  assert:
    that:
      - iptables_state is changed



- name: "fail to restore state from the test file"
  block:
    - name: "restore state from the test file (bad policies, expected error -> rollback)"
      iptables_state:
        path: "{{ iptables_tests }}"
        state: restored
      register: iptables_state
      async: "{{ ansible_timeout }}"
      poll: 0

  rescue:
    - name: "explain expected failure"
      assert:
        that:
          - iptables_state is not changed
          - not iptables_state.applied
        success_msg: >-
          The previous error has been triggered to test the rollback. If you
          are there, it means that 1) connection has been lost right after the
          bad rules have been restored; 2) a rollback happened, so the bad
          rules are not applied, finally; 3) module failed because it didn't
          reach the wanted state, but at least host is not lost !!!
        fail_msg: >-
          The previous error has been triggered but its results are not as
          expected.

- name: "check that the expected failure happened"
  assert:
    that:
      - iptables_state is failed



- name: "fail to restore state from the test file (again)"
  block:
    - name: "try again, with a higher timeout (bad policies, same expected error)"
      iptables_state:
        path: "{{ iptables_tests }}"
        state: restored
      register: iptables_state
      async: "{{ ansible_timeout }}"
      poll: 0
      vars:
        ansible_timeout: "{{ max_delay | d(300) }}"

  rescue:
    - name: "explain expected failure"
      assert:
        that:
          - iptables_state is not changed
          - not iptables_state.applied
        success_msg: >-
          The previous error has been triggered to test the rollback. If you
          are there, it means that 1) connection has been lost right after the
          bad rules have been restored; 2) a rollback happened, so the bad
          rules are not applied, finally; 3) module failed because it didn't
          reach the wanted state, but at least host is not lost !!!
        fail_msg: >-
          The previous error has been triggered but its results are not as
          expected.

- name: "check that the expected failure happened"
  assert:
    that:
      - iptables_state is failed



- name: "restore state from backup (must NOT report a change)"
  iptables_state:
    path: "{{ iptables_saved }}"
    state: restored
  register: iptables_state
  async: "{{ ansible_timeout }}"
  poll: 0

- name: "assert that results are as expected"
  assert:
    that:
      - iptables_state is not changed



- name: "restore state from backup (mangle, must NOT report a change)"
  iptables_state:
    path: "{{ iptables_saved }}"
    table: mangle
    state: restored
  register: iptables_state
  async: "{{ ansible_timeout }}"
  poll: 0

- name: "assert that results are as expected"
  assert:
    that:
      - iptables_state is not changed



- name: "create a blocking ruleset with a REJECT rule"
  copy:
    dest: "{{ iptables_tests }}"
    content: |
      *filter
      -A INPUT -j REJECT
      COMMIT



- name: "fail to restore state from the test file (again)"
  block:
    - name: "restore state from the test file (bad rules, expected error -> rollback)"
      iptables_state:
        path: "{{ iptables_tests }}"
        state: restored
      register: iptables_state
      async: "{{ ansible_timeout }}"
      poll: 0

  rescue:
    - name: "explain expected failure"
      assert:
        that:
          - iptables_state is not changed
          - not iptables_state.applied
        success_msg: >-
          The previous error has been triggered to test the rollback. If you
          are there, it means that 1) connection has been lost right after the
          bad rules have been restored; 2) a rollback happened, so the bad
          rules are not applied, finally; 3) module failed because it didn't
          reach the wanted state, but at least host is not lost !!!
        fail_msg: >-
          The previous error has been triggered but its results are not as
          expected.

- name: "check that the expected failure happened"
  assert:
    that:
      - iptables_state is failed



- name: "fail to restore state from the test file (again)"
  block:
    - name: "try again, with a higher timeout (bad rules, same expected error)"
      iptables_state:
        path: "{{ iptables_tests }}"
        state: restored
      register: iptables_state
      async: "{{ ansible_timeout }}"
      poll: 0
      vars:
        ansible_timeout: "{{ max_delay | d(300) }}"

  rescue:
    - name: "explain expected failure"
      assert:
        that:
          - iptables_state is not changed
          - not iptables_state.applied
        success_msg: >-
          The previous error has been triggered to test the rollback. If you
          are there, it means that 1) connection has been lost right after the
          bad rules have been restored; 2) a rollback happened, so the bad
          rules are not applied, finally; 3) module failed because it didn't
          reach the wanted state, but at least host is not lost !!!
        fail_msg: >-
          The previous error has been triggered but its results are not as
          expected.

- name: "check that the expected failure happened"
  assert:
    that:
      - iptables_state is failed
