Delete a file, create a backup and mark the task as changed when it is

The ansible.builtin.file module doesn’t have a backup option for when files are set to be of state: absent and the isn’t a move module and I would like a backup to be created when deleting files in a loop, I have the file deletion working but I’m struggling to set the changed_when, I have this data:

  php_ver.value.pools:
    www:
      state: absent
    www81:
      state: present

And these loops:

    - name: Debug PHP-FPM pool files that are set to be absent
      ansible.builtin.debug:
        msg: "PHP-FPM pool.d files to be deleted: /etc/php/{{ php_ver.key }}/fpm/pool.d/{{ pool.key }}.conf"
      when: pool.value.state == "absent"
      loop: "{{ php_ver.value.pools | dict2items }}"
      loop_control:
        loop_var: pool
        label: "{{ pool.key }}"

    - name: PHP-FPM pool files absent
      ansible.builtin.shell: |-
        set -e -o pipefail
        if [[ -f "/etc/php/{{ php_ver.key }}/fpm/pool.d/{{ pool.key }}.conf" ]]
        then
          mv /etc/php/{{ php_ver.key }}/fpm/pool.d/{{ pool.key }}.conf \
          /etc/php/{{ php_ver.key }}/fpm/pool.d/{{ pool.key }}.conf.{{ ansible_date_time.iso8601_basic_short }}.bak
          echo "changed"
        else
          echo "notchanged"
        fi
      args:
        executable: /usr/bin/bash
      when: pool.value.state == "absent"
      register: php_fpm_pool_files_absent
      loop: "{{ php_ver.value.pools | dict2items }}"
      loop_control:
        loop_var: pool
        label: "{{ pool.key }}"

    - name: Debug php_fpm_pool_files_absent
      ansible.builtin.debug:
        var: php_fpm_pool_files_absent

This returns the following when there is a change:

TASK [php : PHP-FPM pool files absent] ****************************************************************************************************************************************************************************
task path: /ansible/roles/php/tasks/fpm_version.yml:119
changed: [example.org] => (item=www) => changed=true 
  ansible_loop_var: pool
  cmd: |-
    set -e -o pipefail
    if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
    then
      mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T182921.bak
      echo "changed"
    else
      echo "notchanged"
    fi
  delta: '0:00:00.004122'
  end: '2024-02-29 18:29:41.318263'
  invocation:
    module_args:
      _raw_params: |-
        set -e -o pipefail
        if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
        then
          mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T182921.bak
          echo "changed"
        else
          echo "notchanged"
        fi
      _uses_shell: true
      argv: null
      chdir: null
      creates: null
      executable: /usr/bin/bash
      expand_argument_vars: true
      removes: null
      stdin: null
      stdin_add_newline: true
      strip_empty_ends: true
  msg: ''
  pool:
    key: www
    value:
      state: absent
  rc: 0
  start: '2024-02-29 18:29:41.314141'
  stderr: ''
  stderr_lines: <omitted>
  stdout: changed
  stdout_lines: <omitted>

TASK [php : Debug php_fpm_pool_files_absent] **********************************************************************************************************************************************************************
task path: /ansible/roles/php/tasks/fpm_version.yml:147
ok: [example.org] => 
  php_fpm_pool_files_absent:
    changed: true
    msg: All items completed
    results:
    - ansible_loop_var: pool
      changed: false
      false_condition: pool.value.state == "absent"
      pool:
        key: www81
        value:
          group: www-data
          listen: /run/php/php8.1-fpm.sock
          pm: dynamic
          pm_max_children: '143'
          pm_max_requests: 1000
          pm_max_spare_servers: 3
          pm_min_spare_servers: 1
          pm_process_idle_timeout: 10s
          pm_start_servers: 2
          state: present
          user: www-data
      skip_reason: Conditional result was False
      skipped: true
    - ansible_loop_var: pool
      changed: true
      cmd: |-
        set -e -o pipefail
        if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
        then
          mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T182921.bak
          echo "changed"
        else
          echo "notchanged"
        fi
      delta: '0:00:00.004122'
      end: '2024-02-29 18:29:41.318263'
      failed: false
      invocation:
        module_args:
          _raw_params: |-
            set -e -o pipefail
            if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
            then
              mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T182921.bak
              echo "changed"
            else
              echo "notchanged"
            fi
          _uses_shell: true
          argv: null
          chdir: null
          creates: null
          executable: /usr/bin/bash
          expand_argument_vars: true
          removes: null
          stdin: null
          stdin_add_newline: true
          strip_empty_ends: true
      msg: ''
      pool:
        key: www
        value:
          state: absent
      rc: 0
      start: '2024-02-29 18:29:41.314141'
      stderr: ''
      stderr_lines: []
      stdout: changed
      stdout_lines:
      - changed
    skipped: false

And the following when there isn’t a change:

TASK [php : PHP-FPM pool files absent] ****************************************************************************************************************************************************************************
task path: /ansible/roles/php/tasks/fpm_version.yml:119
changed: [example.org] => (item=www) => changed=true 
  ansible_loop_var: pool
  cmd: |-
    set -e -o pipefail
    if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
    then
      mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T183916.bak
      echo "changed"
    else
      echo "notchanged"
    fi
  delta: '0:00:00.003663'
  end: '2024-02-29 18:39:36.058181'
  invocation:
    module_args:
      _raw_params: |-
        set -e -o pipefail
        if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
        then
          mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T183916.bak
          echo "changed"
        else
          echo "notchanged"
        fi
      _uses_shell: true
      argv: null
      chdir: null
      creates: null
      executable: /usr/bin/bash
      expand_argument_vars: true
      removes: null
      stdin: null
      stdin_add_newline: true
      strip_empty_ends: true
  msg: ''
  pool:
    key: www
    value:
      state: absent
  rc: 0
  start: '2024-02-29 18:39:36.054518'
  stderr: ''
  stderr_lines: <omitted>
  stdout: notchanged
  stdout_lines: <omitted>

TASK [php : Debug php_fpm_pool_files_absent] **********************************************************************************************************************************************************************
task path: /ansible/roles/php/tasks/fpm_version.yml:147
ok: [example.org] => 
  php_fpm_pool_files_absent:
    changed: true
    msg: All items completed
    results:
    - ansible_loop_var: pool
      changed: false
      false_condition: pool.value.state == "absent"
      pool:
        key: www81
        value:
          group: www-data
          listen: /run/php/php8.1-fpm.sock
          pm: dynamic
          pm_max_children: '143'
          pm_max_requests: 1000
          pm_max_spare_servers: 3
          pm_min_spare_servers: 1
          pm_process_idle_timeout: 10s
          pm_start_servers: 2
          state: present
          user: www-data
      skip_reason: Conditional result was False
      skipped: true
    - ansible_loop_var: pool
      changed: true
      cmd: |-
        set -e -o pipefail
        if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
        then
          mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T183916.bak
          echo "changed"
        else
          echo "notchanged"
        fi
      delta: '0:00:00.003663'
      end: '2024-02-29 18:39:36.058181'
      failed: false
      invocation:
        module_args:
          _raw_params: |-
            set -e -o pipefail
            if [[ -f "/etc/php/8.1/fpm/pool.d/www.conf" ]]
            then
              mv /etc/php/8.1/fpm/pool.d/www.conf  /etc/php/8.1/fpm/pool.d/www.conf.20240229T183916.bak
              echo "changed"
            else
              echo "notchanged"
            fi
          _uses_shell: true
          argv: null
          chdir: null
          creates: null
          executable: /usr/bin/bash
          expand_argument_vars: true
          removes: null
          stdin: null
          stdin_add_newline: true
          strip_empty_ends: true
      msg: ''
      pool:
        key: www
        value:
          state: absent
      rc: 0
      start: '2024-02-29 18:39:36.054518'
      stderr: ''
      stderr_lines: []
      stdout: notchanged
      stdout_lines:
      - notchanged
    skipped: false

What I’m struggling with is parsing the results into a true or false for changed_when, does anyone have any suggestions?

Am I making a stupid mistake or is there a far better way to do this?

I apologize if I am way off here, as I am not 100% sure I am answering what you want LOL.

I am not a huge fan of using shell unless absolutely necessary … so couldn’t you do something like:

  • use the ansible.builtin.stat module to check for the existence of file
  • use the ansible.builtin.copy module to copy file (backup) WHEN exists
  • use the ansible.builtin.file module to delete files as originally intended

There’s also options of using something like ansible.posix.synchronize to backup the whole directory if we are talking about tons of files, and it’s easier to do that…

3 Likes

Yes, good point @jrglynn2 I guess I should do that, I believe that is what I have done in the past :roll_eyes: .

It’s not as elegant as what you are trying - but you avoid any potential downfalls of using shell.

I do think it’s worth opening a feature request to add a backup parameter to the ansible.builtin.file module out on the GitHub repository. I think that might be useful. They may have reasons to not want to add it, but it’s worth an ask to force the discussion.

3 Likes

What have you tried for changed_when: so far, and with what results? I would have thought it would be as simple as

      changed_when: php_fpm_pool_files_absent.stdout_lines[0] == 'changed'

For the record, I rather like using shell in cases like this where the extra functionality you need isn’t available in the “standard” modules. If well-written, your shell script can be every bit as robust as a module, and you needn’t complicate your plays with additional tasks. If you do choose to go the shell route, I highly recommend using shellcheck to clean up any issues you might not have thought of. (shellcheck is like ansible-lint for shell scripts.)

2 Likes

This topic was automatically closed 30 days after the last reply. New replies are no longer allowed.