There are few things on which the play's end result depends such as
- Predefined variable value
- Some remote system's fact
- The result of the previous task or play
- On the value of another variable
- Sometimes on the hosts criteria defined in the inventory file
There are various ways we can control execution flow in Ansible.
As part of this tutorial I will be covering 3 most important conditional statements.
when
failed_when
changed_when
When to use when
?
The when clause contains a raw Jinja2 expression without double curly braces.
We use when
statement in the cases like skipping a particular task or step on one of the hosts based on some criteria. For example skipping some config changes if the operating system is a particular version.
Let us understand this by an example. Below is the playbook which will restart the apache service on 3 worker nodes. Out of them 2 are CentOS systems and one is Ubuntu and Apache service name is different on both the flavors.
My inventory file:
master ansible_host=lco-ansible-master.example.com ansible_user=ansible_user ansible_ssh_port=22
worker1 ansible_host=lco-worker1.example.com ansible_user=ansible_user ansible_ssh_port=22
worker2 ansible_host=lco-worker2.example.com ansible_user=ansible_user ansible_ssh_port=22
worker3 ansible_host=ubuntu-server2.example.com ansible_user=ansible_user ansible_ssh_port=22 ansible_python_interpreter=/usr/bin/python3
[workers]
worker1
worker2
worker3
And here is the playbook.
---
- name: Restart Apache Web-Server
hosts: workers
tasks:
- name: Start Apache service on CentOS or RedHat system
service: name=httpd state=restarted enabled=yes
become: yes
when: ansible_os_family == "RedHat"
- name: Start Apache service on Ubuntu Server
service: name=apache2 state=restarted enabled=yes
become: yes
when: ansible_os_family == "Debian"
As you can see above we are putting when
condition to determine the OS family and then accordingly instructing Ansible to start the service.
Let us execute the playbook.
conditionals $ ansible-playbook -i ../myinventory when.yml
PLAY [Restart Apache Web-Server] *******************************************************************************
TASK [Gathering Facts] *****************************************************************************************
ok: [worker2]
ok: [worker1]
ok: [worker3]
TASK [Start Apache service on CentOS or RedHat system] *********************************************************
skipping: [worker3]
changed: [worker2]
changed: [worker1]
TASK [Start Apache service on Ubuntu Server] *******************************************************************
skipping: [worker1]
skipping: [worker2]
changed: [worker3]
PLAY RECAP *****************************************************************************************************
worker1 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
worker2 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
worker3 : ok=2 changed=1 unreachable=0 failed=0 skipped=1 rescued=0 ignored=0
You can see from the above output that Start Apache service on Ubuntu Server
task was skipped when it was running on CentOS servers and vice versa because of the when
condition.
When to use failed_when
?
We can decide when to mark a play as failed using failed_when
conditional statement. Multiple failed_when
conditions can be joined with an implicit and
operator. The task will fail when all conditions are met. Similarly we can use an or
operator to trigger failure when even one condition is met.
Here is our example playbook.
---
- name: Restarting httpd service
hosts: worker1
become: true
gather_facts: false
vars:
service: httpd
tasks:
- shell: systemctl status httpd.service | grep running
args:
warn: false
register: result
failed_when: "'running' in result.stdout"
- service:
name: "{{ service }}"
state: restarted
Here we are checking for the httpd service status. If the service is found running then our task will be marked as fail otherwise it will restart the service.
Let us execute the playbook.
Case 1 - when service was in running state.
conditionals $ ansible-playbook -i ../myinventory failed_when.yml
PLAY [Restarting httpd service] ********************************************************************************
TASK [shell] ***************************************************************************************************
fatal: [worker1]: FAILED! => {"ansible_facts": {"discovered_interpreter_python": "/usr/bin/python"}, "changed": true, "cmd": "systemctl status httpd.service | grep running", "delta": "0:00:00.009251", "end": "2021-01-27 18:42:37.552126", "failed_when_result": true, "msg": "non-zero return code", "rc": 1, "start": "2021-01-27 18:42:37.542875", "stderr": "", "stderr_lines": [], "stdout": "", "stdout_lines": []}
PLAY RECAP *****************************************************************************************************
worker1 : ok=0 changed=0 unreachable=0 failed=1 skipped=0 rescued=0 ignored=0
The task failed since the service was in running state on the client node.
No let us stop the service on client machine.
$ conditionals $ ansible -i ../myinventory worker1 -m shell -a "systemctl stop httpd.service" -b -kK
SSH password:
BECOME password[defaults to SSH password]:
worker1 | CHANGED | rc=0 >>
And run the playbook again.
conditionals $ ansible-playbook -i ../myinventory failed_when.yml
PLAY [Restarting httpd service] ********************************************************************************
TASK [shell] ***************************************************************************************************
changed: [worker1]
TASK [service] *************************************************************************************************
changed: [worker1]
PLAY RECAP *****************************************************************************************************
worker1 : ok=2 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
This time the playbook successfully executed the task and restarted the service as it was found not running.
When to use changed_when
?
When we use shell/command or other modules they reports “changed” status to true or 1
based on whether it thinks it affected machine state.
By verifying the return code or std output we sometimes know that our play did not make any changes on remote system. In those scenarios we just want to override that changed result so that it did not trigger any further action based on that (For e.g. any handlers
to get triggered).
We will cover
handlers
in our upcoming articles.
syntax to use changed_when
: (use it just below your register variable)
changed_when: false
I hope by now you will be comfortable with these three conditional statements.
That's all for now. Hope you like the article. Stay Tuned for more.
Thank you. Happy learning!