Managing errors is one of the major challenges while working with any code, the same goes with ansible. It has its own ways of managing errors, whenever ansible encounters an error it stops the execution by default like most of the programming languages and throws an error, and in most cases, these errors leave the hosts in the undesirable state.
To avoid servers from undergoing into an undesirable state while execution, Ansible came up with the various ways by providing options like ignore_errors, any_errors_fatal, and many more such options. But these parameters are constrained to particular cases and can’t be used everywhere. Also, this way we are not managing the errors, we are just playing safe !!!
BLOCKS COMES TO THE RESCUE !!!
Ansible came up with the solution to this problem using “BLOCKS”. Blocks are the tasks that are logically grouped together to serve the purpose. Consider BLOCKS as the “try” parameter used for exception handling in most of the programming languages. We define those task in blocks which are more prone to cause errors.
EXAMPLE-Let’s take the example of Apache2 installation on the Ubuntu to understand better, here we will be using the apt and service module to install and start the Apache2 service respectively. These two tasks will be defined under a single block and the playbook for the same will look something like
--- - name: exception handling in ansible hosts: web become: true tasks: - name: install and start the apache2 service block: - name: install apache2 apt: name: apache2 update_cache: true state: present - name: enable and restart the apache2 service service: name: apache2 enabled: true state: restarted ...
Here you can see that the multiple tasks are defined under a single block, this way it will be easier to manage the code. As the single block can be managed more easily than individual tasks.
RESCUE & ALWAYS –
Now comes the error handling part, like I have already mentioned that the code which is more prone to throw errors is defined under blocks and in case if the block fails we have the option of “rescue” and “always” which is more or less similar to “catch” and “finally” when compared to other programming languages.
Now, let’s consider due to some reasons the above block fails, in those cases, we can introduce “rescue & always” to manage errors. For the sake of this example, we are printing the message to understand better, although we can use any module in such cases. Now the updated playbook with rescue and always with the debug module will look something like this,
--- - name: exception handling in ansible hosts: web become: true tasks: - name: install and start the apache2 service block: - name: install apache2 apt: name: apache2 update_cache: true state: present - name: enable and restart the apache2 service service: name: apache2 enabled: true state: restarted rescue: - debug: msg: "Hi!!! I will be executed when the block fails" always: - debug: msg: "Hi!!! I will always execute." ...
Here, Also I have created a situation so that the task defined in the block will fail and automatically the tasks defined in “rescue” will be executed( print message is our case). Also, the tasks defined in “always” will be executed every time. Now, after running the playbook the output will look something like-
Here, we can see that one of the tasks in the block fails which leads to failure of the whole block resulting in the calling of rescue and always. And the task defined in rescue and always is executed( message is printed on the console output ).
I hope this post clears out how the playbook got executed successfully, in-spite of the errors. This way it will be more easy for the users to write efficient and error-free playbooks.
Ansible has once again proven its worth!!!
One thought on “ERROR HANDLING IN ANSIBLE”
Thank you for this clear and precise article.
In the book “Ansible for DevOps: Server and Configuration Management for Humans” by Jeff Geerling (2015).
His opinion about block/rescue/always is :
“…Blocks can be very helpful for building reliable playbooks, but just like exceptions in programming
languages, block/rescue/always failure handling can over-complicate things. If it’s easier to
maintain idempotence using failed_when per-task to define acceptable failure conditions, or to
structure your playbook in a different way, it may not be necessary to use block/rescue/always…”
LikeLiked by 1 person