Friday, 12 December 2025

Ansible 21. errro handling with changed_when: false and ignore_errors: yes

Ansible Task Execution Scenarios

This table outlines how different Ansible directives affect the continuation of a play and the final task status when a task reports a non-zero return code (which typically indicates a failure).

ScenarioTask Fails (rc != 0)Play Continues?Failure Status
Default (No Directives)YesNO. (Play stops) (unless in a block with rescue )Task marked failed.
1. ignore_errors: yesYesYES. (Play continues) Output shows FAILED! => ... ignoringTask marked ignored=1 in the final recap, but in the Task execution stage task will be reported as failed and  Ansible proceed with next step.
2. failed_when: falseYesYES. (Play continues)Task marked ok or changed (based on changed_when: false directive ), but never failed.
3. changed_when: falseYesNO. (Play stops) (unless in a block with rescue )Task marked failed (The directive only affects the changed status, not the failed status).

The changed_when: false directive is typically used to prevent a task from reporting a 'changed' status, but it does not prevent a task from failing when its return code is non-zero. Therefore, it behaves like the Default scenario when a failure occurs. 

The ignore_errors: yes tells Ansible: If this task fails (returns a non-zero exit code), report the failure, but keep running the rest of the playbook on this host.

A common use case is running a cleanup command where the file/service might not exist on all hosts, which would cause the task to fail but should not stop the entire play.

Ignore_errors: yes: The task still reports a failed status, but the playbook keeps running. The failure is visible in the output (often marked with ... ignoring).

Failed_when: false: The task is never marked as failed (it reports ok or changed), and the play keeps running. The original failure is completely hidden from Ansible's status tracking.By default, an Ansible task is marked as failed if the underlying command returns a non-zero exit code or if an Ansible module reports an error, applying failed_when: false to a task tells Ansible to never mark that specific task as failed, regardless of the task's normal return code or output.

Let's see an example:

oelggvm01 is my oracle db server and I'm using below ansible playbook to manage my listener.

[oracle@oel01db ansible-project]$ cat ./inventory/hosts

[db_servers]

oelggvm01

[oracle@oel01db ansible-project]$


[oracle@oel01db ansible-project]$ cat ./playbooks/changed.failed.ignore_example.yml
- name: Oracle Listener Health Check (With ignore_errors example)
  hosts: db_servers
  become_user: oracle
  gather_facts: no

  tasks:

    - name: Check listener status
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl status
      register: listener_status
      changed_when: false
      failed_when: false

    - name: Print listener status
      debug:
        msg: "Listener status is: {{ listener_status.stdout }}"

    - name: Stop listener (may already be down)
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl stop
      ignore_errors: yes
      changed_when: false

    - name: Start listener if it is down
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl start
      when: "'TNS-12541' in listener_status.stdout"
      changed_when: true

[oracle@oel01db ansible-project]$


1. lets verify listener is down on the managed node

[oracle@oelggvm01 dbhome_1]$ lsnrctl status

LSNRCTL for Linux: Version 19.0.0.0.0 - Production on 14-DEC-2025 05:35:20

Copyright (c) 1991, 2025, Oracle.  All rights reserved.

Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=TCP)(HOST=192.168.0.111)(PORT=1521)))
TNS-12541: TNS:no listener
 TNS-12560: TNS:protocol adapter error
  TNS-00511: No listener
   Linux Error: 111: Connection refused
Connecting to (DESCRIPTION=(ADDRESS=(PROTOCOL=IPC)(KEY=EXTPROC1521)))
TNS-12541: TNS:no listener
 TNS-12560: TNS:protocol adapter error
  TNS-00511: No listener
   Linux Error: 2: No such file or directory
[oracle@oelggvm01 dbhome_1]$

First I've commented out below highlihgted

[oracle@oel01db ansible-project]$ cat ./playbooks/changed.failed.ignore_example.yml
- name: Oracle Listener Health Check (With ignore_errors example)
  hosts: db_servers
  become_user: oracle
  gather_facts: no

  tasks:

    - name: Check listener status
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl status
      register: listener_status
      #changed_when: false
      failed_when: false

    - name: Print listener status
      debug:
        msg: "Listener status is: {{ listener_status.stdout }}"

    - name: Stop listener (may already be down)
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl stop
      #ignore_errors: yes
      changed_when: false

    - name: Start listener if it is down
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl start
      when: "'TNS-12541' in listener_status.stdout"
      changed_when: true

[oracle@oel01db ansible-project]$




















Here fist task (lsnrctl status) is marked as changed=1  as #changed_when is updated as false

Also the play stopped its execution in the second task as   #ignore_errors: yes 

Next see the effect of commenting failed_when: false from the first task.


[oracle@oel01db ansible-project]$ cat ./playbooks/changed.failed.ignore_example.yml
- name: Oracle Listener Health Check (With ignore_errors example)
  hosts: db_servers
  become_user: oracle
  gather_facts: no

  tasks:

    - name: Check listener status
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl status
      register: listener_status
      #changed_when: false
      #failed_when: false

    - name: Print listener status
      debug:
        msg: "Listener status is: {{ listener_status.stdout }}"

    - name: Stop listener (may already be down)
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl stop
      #ignore_errors: yes
      changed_when: false

    - name: Start listener if it is down
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl start
      when: "'TNS-12541' in listener_status.stdout"
      changed_when: true

[oracle@oel01db ansible-project]$




Here playbook stopped in the first task itself and it is  marked as failed 

Let's remove all comment and re-run

[oracle@oel01db ansible-project]$ cat ./playbooks/changed.failed.ignore_example.yml
- name: Oracle Listener Health Check (With ignore_errors example)
  hosts: db_servers
  become_user: oracle
  gather_facts: no

  tasks:

    - name: Check listener status
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl status
      register: listener_status
      changed_when: false
      failed_when: false

    - name: Print listener status
      debug:
        msg: "Listener status is: {{ listener_status.stdout }}"

    - name: Stop listener (may already be down)
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl stop
      ignore_errors: yes
      changed_when: false

    - name: Start listener if it is down
      environment:
        ORACLE_HOME: /u01/app/oracle/product/19.0.0/dbhome_1
        PATH: /u01/app/oracle/product/19.0.0/dbhome_1/bin
      shell: lsnrctl start
      when: "'TNS-12541' in listener_status.stdout"
      changed_when: true

[oracle@oel01db ansible-project]$





















Now the playbook ignore all error and started listener, please note ignored=1

Verify listener status 

[oracle@oelggvm01 dbhome_1]$ lsnrctl status >/dev/null 2>&1; echo $?

0

[oracle@oelggvm01 dbhome_1]$


No comments:

Post a Comment

Building a Safer PostgreSQL CI/CD Pipeline with GitHub Actions: Dev → PR Review → Test Promotion

In my previous post, we explored a simple push-to-main deployment strategy . While functional, that model is not considered an industry best...