Pages

Thursday, February 11, 2016

Ansible Conditionals

Share it Please

In our previous article we have seen how playbooks work and how tasks defined in the playbooks are executed. But in all these cases we see that Ansible executes the tasks in sequentially. Ansible also provides us conditionals in executing tasks bases on conditions.

For example, let's say you have a playbook that will install Apache HTTPD Server on the remote host. Now, the Apache HTTPD Server has a different package name for a Debian-based operating system, and it's called apache2; for a Red-Hat-based operating system, it's called httpd. But defining multiple playbooks for different flavors of the *nix operating system is waste of time.

Ansible allows us to identify system and execute certain command based on this. Ansible provides conditional statements that help run a task only when a specified condition is met.Ansible provide a WHEN condition to execute tasks based on certain conditions. Lets see a basic example of usin When condition

[root@vx111a with-ansible]# cat with.yml
---
- hosts: dev
  tasks:
    - name: install httpd Package
      yum: name=httpd state=latest
      sudo: yes
      when: ansible_os_family == "Redhat"

    - name: install apache2 package
      apt: name=apache2 state=latest
      sudo: yes
      when: ansible_os_family == "Debian"

The above playbook is basic example of using the when condition. This is similar to if-else loop in the programming syntax. In the above playbook, we first check what the anisble_os_family is. Once we get the details we will then install the necessary Apache packages based on that.

In case if that is Redhat we will go with the HTTPD or apache2 if that is Debain.

Note – Every time Ansible runs a playbook it collects certain details about the remote machine called Facts. This can be disabled when we add the gather_facts: false in our playbook.  This gathers all the necessary details about the remote system including variables, memory and all necessary configurations that are set for the remote machine

The second task in the playbook will install the latest apache2 package if the ansible_os_family is Debian. If the when condition doesn't match a task, then it will simply skip that task and move forward.
Lets run the playbook

[root@vx111a with-ansible]# ansible-playbook with.yml

PLAY [dev] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.202.96]
ok: [172.16.202.97]

TASK: [install httpd Package] *************************************************
skipping: [172.16.202.96]
skipping: [172.16.202.97]

TASK: [install apache2 package] ***********************************************
skipping: [172.16.202.96]
changed: [172.16.202.97]

PLAY RECAP ********************************************************************
172.16.202.96              : ok=1    changed=0    unreachable=0    failed=0  
172.16.202.97              : ok=2    changed=1    unreachable=0    failed=0  

In the above case, the IP (172.16.202.97) is a Debain machine and the other one was a Centos machine.

Ansible allows a variable to register to task that we run on the remote machine. Lets see another example of using the with Condition along with register

[root@vx111a with-ansible]# cat with1.yml
---
- hosts: dev
  tasks:
    - name: Check for File
      command: /usr/bin/cat /tmp/hai
      register:  cat_response
      ignore_errors: yes

    - name: Stop Futher if File is Not available
      fail: msg="File is Not available, Please Create the File First"
      when: cat_response.rc == 2


In the above playbook we have defined a command to run on the remote machine. The command is to “cat /tmp/hai”. We will make sure to capture the output in the variable cat_response using the register module.

Ignore_errors – in some conditions when we run a playbook it may fail due to missing variables or packages or any other reason. What if we want to continue the playbook even though certain tasks defined were failed? . We can use the ignore_errors: yes Condition duing this case. The above condition only governs the return value of failure of the particular task, so if you have an undefined variable used, it will still raise an error that users will need to address. Neither will this prevent failures on connection nor must execution issues, the task be able to run and return a value of ‘failed’.

Now if you check the above playbook we have defined a task to check the Contents of the file /tmp/hai. If the file is not available the task fails and then we have set the ignore_error to yes which will ignore the errors and continue the playbook execution.

Every task that is run will be having a stdout and stderr. Besides these there will some other details too like return code (rc) of the command, command itself, start and end time of the command being executed etc.

- name: Stop Futher if File is Not available
      fail: msg="File is Not available, Please Create the File First"
      when: cat_response.rc == 2

In the above playbook we are checking the return code of the task executed and saved in the cat_response variable. We then used the when condition to make sure that the rc command is equal to 2 , then use the fail module to generate a failure message

Note - Apart from ==, Ansible also supports the >, <, <=, >=, and != operators with the when condition.

Now lets run the playbooks as,

[root@vx111a with-ansible]# ansible-playbook  with1.yml

PLAY [dev] ********************************************************************

GATHERING FACTS ***************************************************************
ok: [172.16.202.96]
ok: [172.16.202.97]

TASK: [Check for File] ********************************************************
failed: [172.16.202.97] => {"cmd": "/usr/bin/cat /tmp/hai", "failed": true, "rc": 2}
msg: [Errno 2] No such file or directory
...ignoring
failed: [172.16.202.96] => {"cmd": "/usr/bin/cat /tmp/hai", "failed": true, "rc": 2}
msg: [Errno 2] No such file or directory
...ignoring

TASK: [Stop Futher if File is Not available] **********************************
failed: [172.16.202.96] => {"failed": true}
msg: File is Not available, Please Create the File First
failed: [172.16.202.97] => {"failed": true}
msg: File is Not available, Please Create the File First

FATAL: all hosts have already failed -- aborting

PLAY RECAP ********************************************************************
           to retry, use: --limit @/root/with1.retry

172.16.202.96              : ok=2    changed=0    unreachable=0    failed=1  
172.16.202.97              : ok=2    changed=0    unreachable=0    failed=1  

We can see fail message output when the playbook is ran. We can also see that though the task failed the execution continued and displayed messages accordingly.


I hope I have given clear examples of using the with Condition in Ansbile.

No comments :

Post a Comment