'How do I create an Ansible "pre-handler" that runs before the task but only if the task needs to run?

How do I create an Ansible "pre-handler" that runs before the task, but only if the task needs to run? In other words, Ansible will first check if the task needs to be run. If it does, it runs the pre-handler and then runs the task. If the task does not need to be run, the pre-handler is never run.

My use case is a root filesystem mounted as read-only. I have an Ansible task to create .bashrc. I would like Ansible to remount the filesystem as read-write if and only if .bashrc needs to be updated. Remounting the filesystem before and after each Ansible run is not practical because making it read-only again requires a reboot.



Solution 1:[1]

A handler is notified by a task if that task changed something. So a "pre-handler" is not possible as the task needs to run to see if it changes something or not.

However, you can notify a handler from a task running in check mode. If you want to do things in order, you'll need to force the run of handlers with the meta module.

Would something like the below example solve your problem ?

- name: Check if .bashrc has the correct content
  copy: &bashrc_copy_params
    src: bashrc_root
    dest: /root/.bashrc
    owner: root
    group: root
    mode: 0644
  check_mode: true
  notify: remount root fs rw

- meta: flush_handlers

- name: Really copy .bashrc
  copy: *bashrc_copy_params

Note that you can achieve the exact same result without a handler in this specific case. Below, an other example with a block that will run only when the check reports a change. It is even better than the previous example as the real copy task will be totally skipped if not needed.

- name: Check if .bashrc has the correct content
  copy: &bashrc_copy_params
    src: bashrc_root
    dest: /root/.bashrc
    owner: root
    group: root
    mode: 0644
  check_mode: true
  register: bashrc_state

- when: bashrc_state.changed | bool
  block:
    - name: remount root fs rw
      debug:
         msg: for example only, replace with your own task

    - name: Really copy .bashrc
      copy: *bashrc_copy_params

Note: The &bashrc_copy_params and *bashrc_copy_params notations in my above examples are yaml anchors. See learn yaml in Y minutes for an explanation if needed. They are allowed in Ansible but must be declared and used in the same file.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1