Error Handling In Ansible Playbook

Ansible Error handling – In this lesson, you will learn the different ways of how to handle failures in Ansible tasks by using the ignore_errors, force_handlers, Ansible blocks, Ansible rescue, and Ansible always directives in a playbook.

How Can Error Handling Be Done In Ansible

Ansible plays and tasks are executed in the order they are defined in a playbook, and by default, if a task fails, the other tasks will not be executed in that order. However, this behavior can be changed with the use of a keyword called “ignore_errors: true“.

This keyword can be added to a play or a task as the case may be. If it is added to a play, it means that all the errors in the tasks associated to a play will be ignored. More so, if it is added to a task, it means all the errors in the task will be ignored.

Well, we learnt about handlers in one of our previous lessons, what about handlers? Yes, this is also applicable to handlers, handlers error can be handled by the keyword, “force_handlers:yes”.

If a task that is supposed to notify a handler fails, the handlers will not be executed. This behavior can also be changed by using the keyword, “force_handler: yes” .

As usual, let’s understand better with examples.

If we were to install the httpd package and the autofs package using a playbook, the name argument will consist of the “httpd” value and the “autofs” value.

Now, we are going to write a playbook, and we will intentionally make an error by making the name argument of autofs containing “autos“.

1. Create a playbook

[lisa@drdev1 ~]$ vim playbook7.yml
- name: Install basic package
  hosts: hqdev1.tekneed.com
  tasks:
     - name: install autofs
       yum:
         name: autos
         state: present
       ignore_errors: true

     - name: install httpd
       yum:
         name: httpd
         state: present

2. Run the playbook

[lisa@drdev1 ~]$ ansible-playbook playbook7.yml

PLAY [Install basic package] ***********************************************************
........
ansible error handling

This playbook we run should have resulted in an error or task failure, and the second task shouldn’t have run because the first task failed, but because we used the “ignore_errors” keyword, the task did not fail and the play run.

Also, remember that you can choose to use the “ignore_errors” keyword at a play level or at a task level. In our case, it was used at the task level.

Again, let’s see an example of how we can use the force_handlers keyword to forcefully run a task with handlers.

1. create a playbook

- name: restarting httpd using handlers
  hosts: hqdev1.tekneed.com
  force_handlers: yes
  tasks:
    - name: restart httpd
      service:
        name: httpd
        state: restarted
      notify: restart httpd

  handlers:
    - name: restart httpd
      service:
        name: httpd
        state: restarted

The force_handler directive will always force handlers to run whether it is called or not. Note that the keyword can only be used at a play level

2. Run the playbook

[lisa@drdev1 ~]$ ansible-playbook playbook3.yml

PLAY [restarting httpd using handlers] ********************************
......

Because the force_handlers directive is set to yes, the handler will always run.

Specifying Task Failure conditions

Ansible may run a task/command successfully, however may be a failure due to the final result a user desires to get. In this sense, one can specify a condition for tasks to fail or in other words, you are at liberty to determine what a failure is.

Let’s see how this can be done by using the “failed_when” directive. The failed_when directive, from its word, simply means the task should fail when a condition is met or not met.

Let’s use the playbook below as an example,

[lisa@drdev1 ~]$ vim playbook5.yml
- name: Web page fetcher
  hosts: hqdev1.tekneed.com
  tasks:
    - name: connect to website
      uri:
        url: https://tekneed.com
        return_content: true
      register: output

    - name: verify content
      debug:
        msg: "verifying content"
      failed_when:
        - '"this content" not in output.content'
        - '"other content" not in output.content'

This is what this playbook will do. The uri module will interact with the webserver and fetch the page, https://www.tekneed.com.
More so, With the true value for the return_content argument, the body of the response of https://tekneed.com will be returned as content, and output will be captured with the aid of the register directive.

For the second task, the content “verifying content” will be printed by the debug module with the aid of the msg argument, and with the “failed_when” directive, the task will fail when the string, “this content” and “other content” is not in the captured output.

Run the playbook

[lisa@drdev1 ~]$ ansible-playbook playbook5.yml

PLAY [Web page fetcher] ************************************************************
.......

Alternatively, the “fail” module can be used to specify when a task fails. This module can only be very useful if the “when” keyword is used to specify the exact failure condition.

Let’s use the same example we used above, but this time around use the “fail” module and “when” keyword

[lisa@drdev1 ~]$ vim playbook5.yml
- name: Web page fetcher
  hosts: hqdev1.tekneed.com
  tasks:
    - name: connect to website
      uri:
        url: https://tekneed.com
        return_content: true
      register: output

    - name: verify content
      fail:
        msg: "verifying content"
      when:
        - '"this content" not in output.content'
        - '"other content" not in output.content'

Run the playbook

[lisa@drdev1 ~]$ ansible-playbook playbook5.yml

PLAY [Web page fetcher] ************************************************************
.......

Managing Changed Status

Managing a changed status can be useful in avoiding unexpected results while running a playbook. Some tasks may even report a changed status and nothing in the real sense has really changed. It could just be that information was retrieved.

In some cases, you may not want a task to result in a changed status. In this case, one needs to use the “changed_when: false” keyword. The playbook will only report “ok” or “failed” status, and will never report a changed status.

An example of such task can be seen below.

- name: copy in nginx conf
  template: src=nginx.conf.j2
            dest=/etc/nginx/nginx.conf

- name: validate nginx conf
  command: nginx -t
  changed_when: false

One can also specify a condition when a task should change, an example of such task is seen in the playbook below.

- name: Web page fetcher
  hosts: hqdev1.tekneed.com
  tasks:
    - name: connect to website
      uri:
        url: https://tekneed.com
        return_content: true
      register: output

    - name: verify content
      fail:
        msg: "verifying content"
      changed_when: "'success' in output.stdout"

Using Ansible Blocks

Blocks are used to group tasks, specific tasks that are related, and can be very useful with a conditional statement.

If tasks are grouped conditionally, and the conditions is/are true, all the tasks will be executed. You should also know that block is a directive in Ansible and not a module, hence the block directive and the when directive will be at the same indentation level.

Let’s see how blocks can be used with examples.

create a playbook

[lisa@drdev1 ~]$ vim playbook8.yml
- name: setting up httpd
  hosts: localhost
  tasks:
    - name: Install start and enable httpd
      block:
      - name: install httpd
        yum:
          name: httpd
          state: present
      - name: start and enable httpd
        service:
          name: httpd
          state: started
          enabled: true
      when: ansible_distribution == "Red Hat"

This playbook will group only two tasks in a block(install and enable httpd). The first task name is “install httpd” while the second task name is “start and enable httpd“. These tasks will only execute if the condition is true, which is, the OS ansible will execute against is/are Red Hat.

Run the playbook

[lisa@drdev1 ~]$ ansible-playbook playbook8.yml

PLAY [setting up httpd] ********************************************************
.......

With this kind of playbook, if the condition fails, other tasks will not be executed. Let’s see how we can use block with rescue and always if we don’t want this type of condition.

Using Ansible block With rescue and always Statement

Apart from blocks being used to group different tasks, they can also be used specifically for error handling with the rescue keyword.

It works in a way that; if a task that is defined in a block fails, the tasks defined in the rescue section will be executed. This is also similar to the ignore_errors keyword.

More so, there is also an always section, this section will always run either the task fails or not. This is also similar to the ignore_errors keyword.

Let’s understand better with examples.

create a playbook.

[lisa@drdev1 ~]$ vim playbook9.yml
- name: setting up httpd
  hosts: localhost
  tasks:
    - name: Install the latest httpd and restart
      block:
        - name: install httpd
          yum:
            name: htt
            state: latest
      rescue:
        - name: restart httpd
          service:
            name: httpd
            state: started
        - name: Install autofs
          yum:
            name: autofs
      always:
        - name: restart autofs
          service:
            name: autofs
            state: started

This playbook will group four tasks in a block(install the latest httpd and restart).
The first task in the block section will fail because the name of the package is incorrect. However, the second and third tasks will run because they are in the rescue section. More so, the fourth task will run because it is in the always section.

Note that you can have as many tasks you want in the block section, rescue section or always section

Run the playbook

[lisa@drdev1 ~]$ ansible-playbook playbook9.yml

PLAY [setting up httpd] *********************************************************
......

Class Activity

create a playbook that contains 1 play with tasks using block, always and rescue statements

If you like this article, you can support us by

1. sharing this article.

2. Buying the article writer a coffee (click here to buy a coffee)

3. Donating to push our project to the next level. (click here to donate)

If you need personal training, send an email to info@tekneed.com

Click To Watch Video On Ansible Error Handling

RHCE EX294 Exam Practice Question On Ansible Error Handling

Suggested: Managing Layered Storage With Stratis – Video

Your feedback is welcomed. If you love others, you will share with others

Be the first to comment

Leave a Reply

Your email address will not be published.


*