In this post, we are going to see how to use conditional statements of Ansible such as when, changed_when, failed_when and where to use them appropriately and how it works. By these conditional modules, Ansible provides a way for us to define when should ansible run a certain task or consider the executed task as Success or failure.
Long Story Short, These modules give us a way to make ansible do something when a certain condition is met or satisfied
let us cover each conditional statements one by one with examples.
We presume that you have all the basic knowledge of Ansible. If not, we highly recommend you to refer the following articles and come back.
Ansible Basics: What is Ansible, Ad hoc commands and Playbooks
Ansible In Action: How setup your own ansible infrastructure using Vagrant and run your playbook
These articles can help you to get started with Ansible.
Find more ansible playbook examples here
The Ansible when Statement
Ansible when statement is more like if statement in any given programming language. It evaluates if a condition is met or satisfied.
Consider yourself having any of the following requirements
- You want to run a task only in a specific box
- You want to run a task based on the output of another task
- You want to skip or proceed with an installation when the OS version is Linux or Ubuntu
- You want to perform some disk clean up tasks when a threshold is reached
- You want to control the execution when a certain value is reached in Loop
More and more. These are all the few test cases or real-time usage scenarios, I could think of. I am certain, there would be more explored and unexplored possibilities for these conditional statements.
How to use ansible when Statement
We are going to provide various examples of how to use ansible when statement , You can choose to read whichever example you would like to read
Example 1: Shutdown the Debian flavoured servers
In the following playbook, we have used a when statement and a command to execute. The Command will only execute when the defined condition is satisfied, which is exactly when the Operating system of the host is Debian
tasks: - name: "shut down Debian flavored systems" command: /sbin/shutdown -t now when: ansible_os_family == "Debian"
Example 2: Install HTTPD when httpd is not installed already
Being aware that shell would return not found error message when the given command is not installed. We are using it as our search keyword to determine the installation of httpd.In this example, we are first making sure whether "Apache httpd" is already installed by running the httpd command over the shell. The output of the command is saved into a register variable named "validatedhttpd
"
When we run the following playbook, The first task will run the command httpd and the result of the command will be stored in "validatehttpd
" register variable.
Then the second task, which is to install httpd using yum module. Will first execute the when condition we have specified and see if it is TRUE.
Therefore, If there is a "not found" error in the register variable. The HTTPD will be installed. If there is anything else. HTTPD will not be installed and the task will be skipped.
--- - hosts: web tasks: - name: "Determine if the HTTPD is installed" register: validatehttpd shell: httpd - name: Ensure Apache is at the Latest version become: yes become_user: root yum: name: httpd state: latest when: 'not found' in validatehttpd.stdout
Example 3: [Multiple Conditions in Single when statement] Shutdown only CentOS-6 and Debian-7
Our requirement here is to shut down only CentOS6 and Debian7 version flavoured systems. So our conditional statement should be as followsAs said earlier, when is more like an if statement so it should support the multiple conditions in a single validation.
(ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
Here we have used parenthesis ( ) for a grouping
The Playbook is given below
--- - hosts: all tasks: - name: "shut down CentOS 6 and Debian 7 systems" command: /sbin/shutdown -t now when: (ansible_distribution == "CentOS" and ansible_distribution_major_version == "6") or (ansible_distribution == "Debian" and ansible_distribution_major_version == "7")
If our requirement is just to validate, If the OS distribution is CentOS and version is 6 , We could write it like this
tasks: - name: "shut down CentOS 6 systems" command: /sbin/shutdown -t now when: - ansible_distribution == "CentOS" - ansible_distribution_major_version == "6"
What we do here is mentioning our conditions in a list and ALL SHOULD BE TRUE for this task to run
The Ansible failed_when and changed_when Statements
Ansible failed_when and changed_when statements are similar to ansible when statement. The only difference is that It will mark the task as failed or Success[changed], when the condition defined, is met or satisfied.
The primary purpose of the failed_when
and changed_when
statements are to determine whether the task is actually successful or failure
Consider you are running a command
or shell
module with some complex script or a simple command.
Ansible would report it as
changed
as long as the command (or) script give ZERO return code.
But how would you decide whether the command or script ran successfully? or met your needs?
For example, When you are starting a Weblogic (or) Tomcat servers using some shell script or command. Ansible would invoke the script and consider it as done (or) changed. But you would never know whether its actually true until you re-validate with wait_for
or debug
module
Let us see some real time practical examples for both failed_when and changed_when statements in the upcoming section
How to use ansible changed_when Statement
Example 1: Start the HTTPD (or) Apache Server which is already started
Having said that, Let's start with our trialWe are going to start the HTTPD (or) Apache Server which is already running. Ideally, If it is already running it should not report as changed
Step 1: Making sure it is already running by invoking the ps -eaf|grep -i httpd
command as ad-hoc
Step 2: Use the following playbook with the task to start the HTTPD server
--- - hosts: web tasks: - name: "Start the Apache HTTPD Server" become: true become_user: root shell: "httpd -k start"
As you could see in the preceding execution output snapshot, The task to start the httpd server has been marked as changed despite it did not actually start the apache and it was already running.
Step 2a: Modified Playbook with Debug Enabled
To know the truth, you should modify the playbook with a debug and register as follows
--- - hosts: web tasks: - name: "Start the Apache HTTPD Server" become: true become_user: root register: starthttpdout shell: "httpd -k start" - debug: msg: "{{starthttpdout.stdout}}"
The execution output of the preceding playbook is given below
Hope the execution output is already self-explanatory. You could see the ansible considering the task as changed when it has not actually started it
Here comes the changed_when
to explicitly tell ansible when to consider the task as Successful (or) changed
Let us re modify our same Playbook with changed_when
Step 3: The Modified Playbook with changed_when
--- - hosts: web tasks: - name: "Start the Apache HTTPD Server" become: true become_user: root register: starthttpdout shell: "httpd -k start" changed_when: "'already running' not in starthttpdout.stdout" - debug: msg: "{{starthttpdout.stdout}}"
We have just added a single line to our previous version of playbook.
changed_when: "'already running' is not in starthttpdout.stdout"
The Execution Output of our new playbook is given below
Now you can notice that the task is GREEN, not YELLOW. In other words, It is unchanged
Example 2: Install Dependencies via PHP Composer
When using PHP Composer as a command to install project dependencies, it’s useful to know when Composer installed something, or when nothing changed. Here’s an example:
- name: Install dependencies via Composer. command: "/usr/local/bin/composer global require phpunit/phpunit --prefer-dist" register: composer changed_when: "'Nothing to install or update' not in composer.stdout"
You can see we used register
to store the results of the command, then we checked whether a certain string was in the registered variable’s stdout.
Only when Composer doesn’t do anything it will print “Nothing to install or update”, so we use that string to determine or to tell Ansible if the task resulted in a change.
How to use ansible failed_when Statement
Example 1: System Requirement / Prerequisite check before Installation
This one is a more real-time scenario every one of us might have come across, During the installation of software, in midway, the installation wizard will fail stating that there is no enough memory (or) the minimum system requirements to install that specific software is not met
As we all know, Every Software needs some minimum system requirements. When they are not met, The installation would fail.
In our case, We are going to take weblogic application server installation as an example.
As per oracle recommendation for weblogic 12c to function properly and for hassle-free installation, The system must meet the following requirement
- 2 GB of Physical Memory ( RAM)
- Minimum 4 GB of Disk space in Domain Directory
/opt
- Minimum 1 GB of disk space in
/tmp
directory
Now we are going to perform a quick pre-requisite check using ansible failed_when and determine whether the system requirement specified above are met
Consider the following playbook
--- - hosts: app tasks: - name: Making sure the /tmp has more than 1gb shell: "df -h /tmp|grep -v Filesystem|awk '{print $4}'|cut -d G -f1" register: tmpspace failed_when: "tmpspace.stdout|float < 1" - name: Making sure the /opt has more than 4gb shell: "df -h /opt|grep -v Filesystem|awk '{print $4}'|cut -d G -f1" register: tmpspace failed_when: "tmpspace.stdout|float < 4" - name: Making sure the Physical Memory more than 2gb shell: "cat /proc/meminfo|grep -i memtotal|awk '{print $2/1024/1024}'" register: memory failed_when: "memory.stdout|float < 2"
The playbook has been created exactly to validate if the system is meeting the oracle recommended System Requirements.
The tasks are programmed to fail when they are not meeting the requirements. This is done using failed_when and a simple math.
Execution Output of the playbook is given below
as shown in the preceding snapshot, The final requirement, The Physical memory is not enough (or) not meeting our requirement of 2gb. You can notice that the system is built with 1gb in the stdout
of the error message
We come to a conclusion, as we have already discussed about all three conditional statements like when, failed_when and changed_when in detail with examples
Hope it is useful and make sense.
Thanks
Sarav AK
Follow me on Linkedin My Profile Follow DevopsJunction onFacebook orTwitter For more practical videos and tutorials. Subscribe to our channel
Signup for Exclusive "Subscriber-only" Content