Saturday, 13 December 2025

Ansible 24. error handling Block/Rescue/Always example

Below is a practical Ansible example where:

  • Block:
    Try to alter a database parameter using SYS user.

  • Rescue:
    If SYS connection fails (ORA error, account lock, password issue etc), do the same change via system user.

  • Always:
    Log the result no matter what


1. Create a vault to store the sys/system credentials. 

[oracle@oel01db ansible-project]$ cat oracle-secret-vault.yml
db_system_password: Welcome999
db_sys_password: Jeep#1234
[oracle@oel01db ansible-project]$ ansible-vault encrypt oracle-secret-vault.yml
New Vault password:
Confirm New Vault password:
Encryption successful
[oracle@oel01db ansible-project]$

Create a secret file to store the vault password.

[oracle@oel01db ansible-project]$ cat ~/.vault_pass
oracle
[oracle@oel01db ansible-project]$

Below is my inventory, oelggvm01 is my oracle db server.

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

Copy the vault file to playbooks directory as ansible-playbook command expect this file in the playbooks direcotry.

[oracle@oel01db ansible-project]$ cp oracle-secret-vault.yml  ./playbooks/


2. Create a playbook 


[oracle@oel01db ansible-project]$ cat ./playbooks/Block-Rescue-Always-example.yml
- name: Oracle DB task to alter FRA and verify (Dynamic SID with SYS -> SYSTEM fallback)
  hosts: db_servers
  gather_facts: no
  vars_files:
    - oracle-secret-vault.yml

  tasks:

    ############################################################
    # 1. Get ORACLE_SID dynamically
    ############################################################
    - name: Get the primary ORACLE_SID dynamically
      shell: |
        ps -ef | grep ora_smon | grep -v grep | awk -F_ '{print $3}'
      register: oratab_sid_result
      changed_when: false

    - name: Set the ORACLE_SID variable
      set_fact:
        dynamic_oracle_sid: "{{ oratab_sid_result.stdout | trim }}"

    ############################################################
    # 2. BLOCK / RESCUE / ALWAYS (DB-level fallback only)
    ############################################################
    - block:

        ########################################################
        # BLOCK: SYSDBA
        ########################################################
        - name: Alter FRA using SYSDBA
          shell: |
            export ORACLE_SID={{ dynamic_oracle_sid }}
            export ORAENV_ASK=NO
            . /usr/local/bin/oraenv

            sqlplus -s sys/{{ db_sys_password }}@{{ dynamic_oracle_sid }} as sysdba <<EOF
            alter system set db_recovery_file_dest_size=50G scope=both;
            show parameter db_recovery_file_dest_size;
            exit;
            EOF
          register: fra_block_result
          failed_when: fra_block_result.rc != 0

      rescue:

        ########################################################
        # RESCUE: SYSTEM user
        ########################################################
        - name: Alter FRA using SYSTEM user (fallback)
          shell: |
            export ORACLE_SID={{ dynamic_oracle_sid }}
            export ORAENV_ASK=NO
            . /usr/local/bin/oraenv

            sqlplus -s system/{{ db_system_password }}@{{ dynamic_oracle_sid }} <<EOF
            alter system set db_recovery_file_dest_size=50G scope=both;
            show parameter db_recovery_file_dest_size;
            exit;
            EOF
          register: fra_rescue_result

      always:

        ########################################################
        # ALWAYS: Verification / logging
        ########################################################
        - name: Display FRA verification output
          debug:
            msg: |
              SID={{ dynamic_oracle_sid }}
              BLOCK_RC={{ fra_block_result.rc | default('N/A') }}
              RESCUE_RC={{ fra_rescue_result.rc | default('N/A') }}

              OUTPUT:
              {{ (fra_rescue_result.stdout_lines
              if fra_rescue_result is defined
              else fra_block_result.stdout_lines) }}
[oracle@oel01db ansible-project]$


3. Ran the playbook.

I ran the playbook while sys account is in OPEN state, so that BLOCK will be executed.

[oracle@oel01db ansible-project]$  ansible-playbook -i ./inventory/hosts ./playbooks/Block-Rescue-Always-example.yml --vault-password-file ~/.vault_pass


















In this case rescue block is not ran , let's lock the sys account so that block section will fail .


SQL> alter user sys account lock;

User altered.

SQL>  select username ,account_status from dba_users where username='SYS';

USERNAME     ACCOUNT_STATUS
------------ --------------------------------
SYS          LOCKED

SQL>


Let's  re-run the playbook.


























As we can see, the BLOCK section failed, and the RESCUE section was successfully executed.


rescued=1 means:

One task (or more) in the playbook failed in a block, but the rescue section successfully ran to handle the failure.

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...