# Test code for the sysctl module.
# (c) 2017, James Tanner <tanner.jc@gmail.com>

# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.

# NOTE: Testing sysctl inside an unprivileged container means that we cannot
# apply sysctl, or it will always fail, because of that in most cases (except
# those when it should fail) we have to use `reload=no`.

- name: Test inside Docker
  when:
    - ansible_facts.virtualization_type == 'docker' or ansible_facts.virtualization_type == 'container'
  block:
    - set_fact:
        output_dir_test: "{{ output_dir }}/test_sysctl"

    - name: make sure our testing sub-directory does not exist
      file:
        path: "{{ output_dir_test }}"
        state: absent

    - name: create our testing sub-directory
      file:
        path: "{{ output_dir_test }}"
        state: directory

    ##
    ## sysctl - file manipulation
    ##

    - name: copy the example conf to the test dir
      copy:
        src: sysctl.conf
        dest: "{{ output_dir_test }}"

    - name: Set vm.swappiness to 5
      sysctl:
        name: vm.swappiness
        value: 5
        state: present
        reload: no
        sysctl_file: "{{ output_dir_test }}/sysctl.conf"
      register: sysctl_test0

    - debug:
        var: sysctl_test0
        verbosity: 1

    - name: get file content
      shell: "cat {{ output_dir_test }}/sysctl.conf | egrep -v ^\\#"
      register: sysctl_content0

    - debug:
        var: sysctl_content0
        verbosity: 1

    - name: Set vm.swappiness to 5 again
      sysctl:
          name: vm.swappiness
          value: 5
          state: present
          reload: no
          sysctl_file: "{{ output_dir_test }}/sysctl.conf"
      register: sysctl_test1

    - name: validate results
      assert:
          that:
            - sysctl_test0 is changed
            - sysctl_test1 is not changed
            - 'sysctl_content0.stdout_lines[sysctl_content0.stdout_lines.index("vm.swappiness=5")] == "vm.swappiness=5"'

    - name: Remove kernel.panic
      sysctl:
        name: kernel.panic
        value: 2
        reload: no
        state: absent
        sysctl_file: "{{ output_dir_test }}/sysctl.conf"
      register: sysctl_test2

    - name: get file content
      shell: "cat {{ output_dir_test }}/sysctl.conf | egrep -v ^\\#"
      register: sysctl_content2

    - debug:
        var: item
        verbosity: 1
      with_items:
        - "{{ sysctl_test2 }}"
        - "{{ sysctl_content2 }}"

    - name: Validate results for key removal
      assert:
        that:
          - sysctl_test2 is changed
          - "'kernel.panic' not in sysctl_content2.stdout_lines"

    - name: Test remove kernel.panic again
      sysctl:
        name: kernel.panic
        value: 2
        state: absent
        reload: no
        sysctl_file: "{{ output_dir_test }}/sysctl.conf"
      register: sysctl_test2_change_test

    - name: Assert that no change was made
      assert:
        that:
          - sysctl_test2_change_test is not changed

    - name: Try sysctl with an invalid name
      sysctl:
        name: test.invalid
        value: 1
      register: sysctl_test3
      ignore_errors: yes

    - debug:
        var: sysctl_test3
        verbosity: 1

    - name: validate results for test 3
      assert:
        that:
          - sysctl_test3 is failed

    ##
    ## sysctl - sysctl_set
    ##

    - name: set net.ipv4.ip_forward
      sysctl:
        name: net.ipv4.ip_forward
        value: 1
        sysctl_set: yes
        reload: no
      register: sysctl_test3

    - name: check with sysctl command
      shell: sysctl net.ipv4.ip_forward
      register: sysctl_check3

    - debug:
        var: item
        verbosity: 1
      with_items:
        - "{{ sysctl_test3 }}"
        - "{{ sysctl_check3 }}"

    - name: validate results for test 3
      assert:
        that:
          - sysctl_test3 is changed
          - 'sysctl_check3.stdout_lines == ["net.ipv4.ip_forward = 1"]'

    - name: Try sysctl with no name
      sysctl:
        name:
        value: 1
        sysctl_set: yes
      ignore_errors: True
      register: sysctl_no_name

    - name: validate nameless results
      assert:
        that:
          - sysctl_no_name is failed
          - "sysctl_no_name.msg == 'name cannot be None'"

    - name: Try sysctl with no value
      sysctl:
        name: Foo
        value:
        sysctl_set: yes
      ignore_errors: True
      register: sysctl_no_value

    - name: validate nameless results
      assert:
        that:
          - sysctl_no_value is failed
          - "sysctl_no_value.msg == 'value cannot be None'"

    - name: Try sysctl with an invalid name
      sysctl:
        name: test.invalid
        value: 1
        sysctl_set: yes
      register: sysctl_test4
      ignore_errors: yes

    - debug:
        var: sysctl_test4
        verbosity: 1

    - name: validate results for test 4
      assert:
        that:
          - sysctl_test4 is failed


- name: Test on RHEL VMs
  when:
    - ansible_facts.virtualization_type != 'docker'
    - ansible_facts.distribution == 'RedHat'
  block:
    # Test reload: yes
    - name: Set sysctl property using module
      sysctl:
        name: vm.swappiness
        value: '22'
        state: present
        reload: yes
      register: sysctl_set1

    - name: Change sysctl property using command
      command: sysctl vm.swappiness=33

    - name: Set sysctl property using module
      sysctl:
        name: vm.swappiness
        value: '22'
        state: present
        reload: yes
      register: sysctl_set2

    - name: Read /etc/sysctl.conf
      command: 'egrep -v ^# /etc/sysctl.conf'
      register: sysctl_conf_content

    - name: Get current value of vm.swappiness
      command: sysctl -n vm.swappiness
      register: sysctl_current_vm_swappiness

    - name: Ensure changes were made appropriately
      assert:
        that:
          - sysctl_set1 is changed
          - sysctl_set2 is changed
          - "'vm.swappiness=22' in sysctl_conf_content.stdout_lines"
          - sysctl_current_vm_swappiness.stdout == '22'

    # Test reload: yes in check mode
    - name: Set the same value using module in check mode
      sysctl:
        name: vm.swappiness
        value: '22'
        state: present
        reload: yes
      check_mode: yes
      register: sysctl_check_mode1

    - name: Set a different value using module in check mode
      sysctl:
        name: vm.swappiness
        value: '44'
        state: present
        reload: yes
      check_mode: yes
      register: sysctl_check_mode2

    - name: Read /etc/sysctl.conf
      command: 'egrep -v ^# /etc/sysctl.conf'
      register: sysctl_check_mode_conf_content

    - name: Get current value of vm.swappiness
      command: sysctl -n vm.swappiness
      register: sysctl_check_mode_current_vm_swappiness

    - name: Ensure no changes were made in check mode
      assert:
        that:
          - sysctl_check_mode1 is success
          - sysctl_check_mode2 is changed
          - "'vm.swappiness=22' in sysctl_check_mode_conf_content.stdout_lines"
          - sysctl_check_mode_current_vm_swappiness.stdout == '22'

    # Test sysctl: invalid value
    - name: Set invalid sysctl property using module
      sysctl:
        name: vm.mmap_rnd_bits
        value: '1024'
        state: present
        reload: yes
        sysctl_set: True
      ignore_errors: True
      register: sysctl_invalid_set1

    - name: Read /etc/sysctl.conf
      command: 'cat /etc/sysctl.conf'
      register: sysctl_invalid_conf_content

    - name: Ensure changes were not made
      assert:
        that:
          - sysctl_invalid_set1 is failed
          - "'vm.mmap_rnd_bits' not in sysctl_invalid_conf_content.stdout"
