Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to write an Ansible role task that only runs when any of the previous other tasks in the task file have been changed?

I am working on a role where I want one task to be run at the end of the tasks file if and only if any of the previous tasks in that task file have changed.

For example, I have:

- name: install package
  apt: name=mypackage state=latest

- name: modify a file
  lineinfile: do stuff

- name: modify a second file
  lineinfile: other stuff

- name: restart if anything changed
  service: name=mypackage state=restarted

... and I want to only restart the service if an update has been installed or any of the config files have been changed.

How can I do this?

like image 484
rasebo Avatar asked Jul 01 '16 11:07

rasebo


People also ask

How do I run a specific part of my playbook in Ansible?

The easiest way to run only one task in Ansible Playbook is using the tags statement parameter of the “ansible-playbook” command. The default behavior is to execute all the tags in your Playbook with --tags all .

How do you run task only once in Ansible?

Ansible run_once parameter is used with a task, which you want to run once on first host. When used, this forces the Ansible controller to attempt execution on first host in the current hosts batch, then the result can be applied to the other remaining hosts in current batch.

Which roles tasks or variables adds them to an Ansible playbook dynamically?

Importing roles, tasks, or playbooks adds them to a playbook statically. Ansible pre-processes imported files and roles before it runs any tasks in a playbook, so imported content is never affected by other tasks within the top-level playbook.


1 Answers

Best practice here is to use handlers.

In your role create a file handlers/main.yml with the content:

- name: restart mypackage   service: name=mypackage state=restarted 

Then notify this handler from all tasks. The handler will be notified only if a task reports a changed state (=yellow output)

- name: install package   apt: name=mypackage state=latest   notify: restart mypackage  - name: modify a file   lineinfile: do stuff   notify: restart mypackage  - name: modify a second file   lineinfile: other stuff   notify: restart mypackage 

Handlers will be executed at the very end of your play. If you have other roles involved which depend on the restarted mypackage service, you might want to flush all handlers at the end of the role:

- meta: flush_handlers 

Additionally have a look at the force_handlers setting. In case an error happens in any other role processed after your mypackge role, the handler would not be triggered. Set force_handlers=True in your ansible.cfg to still force your handlers to be executed after errors. This is a very important topic since when you run your playbook the next time the files will not be changed and therefore the handler not get notified, hence your service never restarted.


You can also do this without handlers but this is very ugly. You need to register the output of every single task so you can later check the state in the condition applied to the restart task.

- name: install package   apt: name=mypackage state=latest   register: mypackage_1  - name: modify a file   lineinfile: do stuff   register: mypackage_2  - name: modify a second file   lineinfile: other stuff   register: mypackage_3  - name: restart if anything changed   service: name=mypackage state=restarted   when: mypackage_1 is changed or mypackage_2 is changed or mypackage_3 is changed 

It was possible to use mypackage_1 | changed till ansible 2.9

See also the answer to Ansible Handler notify vs register.

like image 71
udondan Avatar answered Sep 22 '22 06:09

udondan