Since I enjoy automation and finding ways to simplify DBA tasks, I use Ansible for Oracle Database and Grid Infrastructure patching. In my previous posts, I explained why we prefer Ansible and how orchestration benefits us, so I won’t repeat those details here. Instead, I’d like to announce that I’ve updated my Ansible playbooks for the Oracle 19.26 Release Update.
We choose to follow Release Updates with one version behind from latest one, and apply latest MRP (Monthly Release Update) on top.
This new version comes with:
- MRP (Monthly Recommended Patches of April 2025)
- Oracle Database 19c and 23ai Important Recommended One-off Patches (Doc Id 555.1)
- Full compatibility with Oracle RAC environments
What’s New in This Version?
Involves January 2025 RU (19.26)
Included recommended one-off patches from Oracle Support Note 555.1
Precheck enhancements (Required space)
Designed and tested with RAC clusters in mind
GitHub Repository :
Insane-DBAs-Backpack – Latest Ansible Playbooks for Oracle Database Release Updates
Inside you’ll find:
Playbooks for Oracle Grid Infrastructure patching
Playbooks for Oracle Database patching
Optimized for multi-node RAC setups
Why This Matters?
While patching takes time, doing it with Ansible brings simplicity, repeatability, and peace of mind. These playbooks are what I currently use and update over time, especially as new RUs and one-offs release from Oracle.
If you’re into automation like I am, give them a try in your test environment.
Related Posts for How to ?
Oracle Grid Patching by using Ansible
Oracle Database Patching by Using Ansible
Automate Oracle Database Patching with Ansible Playbooks – 19.24
Grid Release Update Playbooks:
For Grid Infrastructure patching, you’ll need to download the following setup files from Oracle Support. Place them under the /u01/app/Setup directory, which should be owned by the ansible user. That’s all for the preparation phase. For a more detailed explanation, you can refer to my blog post: Oracle Grid Patching by using Ansible.
- Grid Home Setup – LINUX.X64_193000_grid_home.zip
- Grid Infrastructure Release Update 19.26.0.0.250121 37257886 (GIRU System Patch involves DBRU) – p37257886_190000_Linux-x86-64.zip
- GI MRP 19.26.0.0.250415 37769929 (GIMRP involve Database Montly Recommended Paches) – p37769929_1926000DBRU_Linux-x86-64.zip
- OPatch 12.2.0.1.46 (Version 46) – p6880880_122010_Linux-x86-64.zip
- Recommended one of patch 34672698 – p34672698_1922000DBRU_Linux-x86-64.zip
- Recommended one of patch 37669540 – p37669540_1926000DBRU_Linux-x86-64.zip
To begin and finish the patching process, simply run the main playbook. It will complete all necessary steps with a single command:
[ansible@blt01 ansible]$ ansible-playbook -i hosts projects/dbru/apply_grid_update_main.yml
[ansible@blt01 ansible]$ cat projects/dbru/apply_grid_update_main.yml
- name: Import playbook to prepare new Oracle Grid Infrastructure Home
ansible.builtin.import_playbook: prepare_grid_allnodes.yml
- name: Import playbook to apply Oracle Grid Infrastructure Release Update
ansible.builtin.import_playbook: apply_giru_onfirstnode.yml
- name: Import playbook to finish Oracle Grid Infrastructure Release Update
ansible.builtin.import_playbook: finish_giru_allnodes.yml
- name: Import playbook to start Database Recovery Process on Standby Databases
ansible.builtin.import_playbook: start_recover_allnodes.yml
- name: Import playbook to remove old grid home
ansible.builtin.import_playbook: remove_giru_allnodes.yml
Playbook contents:
Prepare Step – prepare_grid_allnodes.yml
- name: Prepare new grid home directories
hosts: dbservers
remote_user: root
vars:
new_grid_home: /u01/app/19.26/grid
patch_dir: /u01/app/Setup
tasks:
- name: Ensure patch directory exists
ansible.builtin.file:
path: "{{ patch_dir }}"
state: directory
owner: oracle
group: oinstall
- name: Ensure new grid home directory exists
ansible.builtin.file:
path: "{{ new_grid_home }}"
state: directory
owner: oracle
group: oinstall
Apply Grid Infrastructure Release Update using Out of Place Patching – apply_giru_onfirstnode.yml
- name: Apply Oracle Grid Infrastructure Release Update
hosts: dbservers
remote_user: oracle
run_once: true
vars:
u01_size_mb: 13356
new_grid_home: /u01/app/19.26/grid
old_grid_home: /u01/app/19.24/grid
patch_dir: /u01/app/Setup
source_patch_dir: /u01/app/Setup
tasks:
- name: Copy setup files to target server
ansible.builtin.copy:
src: "{{ source_patch_dir }}/"
dest: "{{ patch_dir }}/"
owner: oracle
group: oinstall
- name: Unzip new grid home
ansible.builtin.unarchive:
src: "{{ patch_dir }}/LINUX.X64_193000_grid_home.zip"
dest: "{{ new_grid_home }}"
remote_src: yes
- name: Unzip OPatch to new grid home
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p6880880_122010_Linux-x86-64.zip"
dest: "{{ new_grid_home }}"
remote_src: yes
- name: Prepare patches directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: oracle
group: oinstall
loop:
- "{{ patch_dir }}/GIRU"
- "{{ patch_dir }}/GIRUOneOff"
- "{{ patch_dir }}/GIMRP"
- name: Unzip GIRU system patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37257886_190000_Linux-x86-64.zip"
dest: "{{ patch_dir }}/GIRU"
remote_src: yes
- name: Unzip GIMRP patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37769929_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/GIMRP"
remote_src: yes
- name: Unzip GIRU oneoff patch ORA-800
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p34672698_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/GIRUOneOff"
remote_src: yes
- name: Unzip GIRU oneoff patch Resync Hanging
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37669540_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/GIRUOneOff"
remote_src: yes
- name: Register cluster nodes for response file
ansible.builtin.shell:
cmd: "{{ old_grid_home }}/bin/olsnodes | tr '\n' ',' | sed 's/,$//'"
register: cluster_nodes
- name: Register OSDBA value for response file
ansible.builtin.shell:
cmd: "grep 'OSDBA=' {{ old_grid_home }}/install/response/grid_20*.rsp"
register: osdba
- name: Register OSOPER value for response file
ansible.builtin.shell:
cmd: "grep 'OSOPER=' {{ old_grid_home }}/install/response/grid_20*.rsp"
register: osoper
- name: Register OSASM value for response file
ansible.builtin.shell:
cmd: "grep 'OSASM=' {{ old_grid_home }}/install/response/grid_20*.rsp"
register: osasm
- name: Create contents of response file
ansible.builtin.copy:
dest: "{{ patch_dir }}/grid_oop.rsp"
content: |
oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0
INVENTORY_LOCATION=/u01/app/oraInventory
oracle.install.option=CRS_SWONLY
ORACLE_BASE=/u01/app/oracle
{{ osdba.stdout }}
{{ osoper.stdout }}
{{ osasm.stdout }}
oracle.install.crs.config.clusterNodes={{ cluster_nodes.stdout }}
ORACLE_HOME={{ new_grid_home }}
oracle.install.crs.config.ClusterConfiguration=STANDALONE
oracle.install.crs.config.configureAsExtendedCluster=false
oracle.install.crs.config.gpnp.configureGNS=false
oracle.install.crs.config.autoConfigureClusterNodeVIP=false
- name: Clean up grid_home setup zip files
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- "{{ patch_dir }}/LINUX.X64_193000_grid_home.zip"
- "{{ patch_dir }}/p34672698_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p37257886_190000_Linux-x86-64.zip"
- "{{ patch_dir }}/p37769929_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p37669540_1926000DBRU_Linux-x86-64.zip"
- name: Check u01 free disk space
ansible.builtin.shell:
cmd: "df -P /u01 | awk 'END { print $4 }'"
register: u01size
failed_when: u01size.stdout | int < u01_size_mb * 1024
- name: Apply GIRU and oneoffs
ansible.builtin.shell:
cmd: |
{{ new_grid_home }}/gridSetup.sh -silent \
-ignorePrereqFailure -waitforcompletion \
-applyRU {{ patch_dir }}/GIRU/37257886 \
-applyOneOffs {{ patch_dir }}/GIMRP/37769929/36124707,{{ patch_dir }}/GIMRP/37769929/36534155,{{ patch_dir }}/GIMRP/37769929/36813092,{{ patch_dir }}/GIMRP/37769929/37421153,{{ patch_dir }}/GIMRP/37769929/37694630,{{ patch_dir }}/GIMRP/37769929/37792660,{{ patch_dir }}/GIRUOneOff/34672698,{{ patch_dir }}/GIRUOneOff/37669540 \
-responsefile {{ patch_dir }}/grid_oop.rsp
environment:
CV_ASSUME_DISTID: OL7
NEWGRIDHOME: "{{ new_grid_home }}"
register: apply_giru
failed_when: "'Successfully Setup Software' not in apply_giru.stdout"
- name: Clean up grid_home setup and patch files directory and contents
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- "{{ patch_dir }}/GIRU"
- "{{ patch_dir }}/GIRUOneOff"
- "{{ patch_dir }}/GIMRP"
- name: Output patching success message
ansible.builtin.debug:
msg: "Patching succeeded. InsaneDBA was here."
when: apply_giru.rc in [6,0]
Switch to new Grid Home – finish_giru_allnodes.yml
- name: Finish Oracle Grid Infrastructure Release Update
hosts: dbservers
remote_user: root
vars:
crs_value: CRS="true"/>
new_grid_home: /u01/app/19.26/grid
old_grid_home: /u01/app/19.24/grid
patch_dir: /u01/app/Setup
tasks:
- name: Register cluster nodes for response file
ansible.builtin.shell:
cmd: "{{ old_grid_home }}/bin/olsnodes | tr '\n' ',' | sed 's/,$//'"
register: cluster_nodes
- name: Tag the new grid home in inventory
ansible.builtin.shell:
cmd: |
$NEWGRIDHOME/gridSetup.sh -silent \
-switchGridHome oracle.install.option=CRS_SWONLY \
ORACLE_HOME={{ new_grid_home }} \
oracle.install.crs.config.clusterNodes={{ cluster_nodes.stdout }} \
oracle.install.crs.rootconfig.executeRootScript=false
become: yes
become_user: oracle
environment:
NEWGRIDHOME: "{{ new_grid_home }}"
- name: Check CRS flag in inventory
ansible.builtin.shell:
cmd: |
grep "{{ new_grid_home }}" /u01/app/oraInventory/ContentsXML/inventory.xml |
grep CRS |
awk 'END { print $6 }'
register: crsflag
failed_when: crsflag.stdout != crs_value
- name: Execute root.sh and start grid from new home
ansible.builtin.command:
cmd: "{{ new_grid_home }}/root.sh"
throttle: 1
- name: Remove response file from stage directory
ansible.builtin.file:
path: "{{ patch_dir }}/grid_oop.rsp"
state: absent
- name: Copy old grid home dependent files to the new grid home
ansible.builtin.copy:
src: "{{ old_grid_home }}/sqlplus/admin/glogin.sql"
dest: "{{ new_grid_home }}/sqlplus/admin/"
owner: oracle
group: oinstall
remote_src: yes
- name: Replace old_grid_home value in .bashrc files with the new_gridhome value
ansible.builtin.replace:
path: "{{ item }}"
regexp: "{{ old_grid_home }}"
replace: "{{ new_grid_home }}"
loop:
- /root/.bashrc
- /home/oracle/.bashrc
Start Database Recovery Process on Standby Databases – it will only run on standby databases, otherwise it will not do anything. start_recover_allnodes.yml
- name: Start Database Recovery Process on Standby Databases
hosts: dbservers
remote_user: oracle
vars:
db_home: /u01/app/oracle/product/19.24/dbhome_1
recovery_script_dest_dir: /home/oracle
recovery_script_dir: /etc/ansible/projects
patch_dir: /u01/app/Setup
tasks:
- name: Register instances
ansible.builtin.shell: "ps -ef | grep ora_pmon | grep -v grep | awk '{ print $NF }' | cut -c10-50"
register: find_instances
- name: Copy start recovery file to remote server
ansible.builtin.copy:
src: "{{ recovery_script_dir }}/start_recover_onremote.sh"
dest: "{{ recovery_script_dest_dir }}"
owner: oracle
group: oinstall
mode: '0750'
- name: Debug List found instances
ansible.builtin.debug:
msg: "Found database instance: {{ item }}"
loop: "{{ find_instances.stdout_lines }}"
- name: Start recovery
ansible.builtin.shell: "{{ recovery_script_dest_dir }}/start_recover_onremote.sh {{ item }} {{ db_home }}"
loop: "{{ find_instances.stdout_lines }}"
register: recovery_output
- name: Debug Recovery output
ansible.builtin.debug:
var: item.stdout
loop: "{{ recovery_output.results }}"
Optional : Remove Old Grid Home – remove_giru_allnodes.yml
- name: Deinstall Oracle Grid Infrastructure
hosts: dbservers
remote_user: root
vars:
removed_value: 'REMOVED="T"'
old_grid_home: /u01/app/19.24/grid
patch_dir: /u01/app/Setup
ansible_python_interpreter: /usr/bin/python3
tasks:
- name: Create response file for silent deinstallation
ansible.builtin.shell:
cmd: "{{ old_grid_home }}/deinstall/deinstall -checkonly"
become: yes
become_user: oracle
become_method: su
throttle: 1
- name: Register old grid_home response file for deinstallation
ansible.builtin.shell:
cmd: "ls -lsrt /tmp/deinstall*/response/*.rsp | tail -1 | awk '{print $NF}'"
register: oldgridresponse
- name: Unlock old grid_home for deinstallation
ansible.builtin.shell:
cmd: "{{ old_grid_home }}/crs/install/rootcrs.sh -unlock -crshome {{ old_grid_home }} -paramfile {{ oldgridresponse.stdout }}"
- name: Recursively change ownership of old_grid_home directory
ansible.builtin.file:
path: "{{ old_grid_home | dirname }}"
state: directory
recurse: yes
owner: oracle
group: oinstall
- name: Deinstall old grid_home
ansible.builtin.expect:
command: "/bin/bash -c '{{ old_grid_home }}/deinstall/deinstall'"
responses:
'Do you want to continue': 'y'
echo: yes
timeout: 600
become: yes
become_user: oracle
run_once: true
register: deinstall_result
- name: Check inventory whether old_grid_home is tagged with removed flag
ansible.builtin.shell:
cmd: "grep '{{ old_grid_home }}' /u01/app/oraInventory/ContentsXML/inventory.xml | awk '{ print $NF }'"
register: removedflag
- name: Remove old grid_home directory
ansible.builtin.file:
path: "{{ old_grid_home | dirname }}"
state: absent
when: deinstall_result.rc == 0 or removedflag.stdout == removed_value
Database Release Update Playbooks:
For Database patching, you’ll need to download the following setup files from Oracle Support. Place them under the /u01/app/Setup directory, which should be owned by the ansible user. That’s all for the preparation phase. For a more detailed explanation, you can refer to my blog post: Oracle Database Patching by Using Ansible.
- Database home Setup – LINUX.X64_193000_db_home.zip
- Grid Infrastructure Release Update 19.26.0.0.250121 37257886 (GIRU System Patch involves DBRU) – p37257886_190000_Linux-x86-64.zip
- GI MRP 19.26.0.0.250415 37769929 (GIMRP involve Database Montly Recommended Paches) – p37769929_1926000DBRU_Linux-x86-64.zip
- OPatch 12.2.0.1.46 (Version 46) – p6880880_122010_Linux-x86-64.zip
- Data Pump Bundle Patch – p37470729_1926000DBRU_Generic.zip
- Spatial Bundle Patch – p37641238_1926000DBRU_Linux-x86-64.zip
- OJVM Patch – p37102264_190000_Linux-x86-64.zip
- Flashback Unusable Indexes Bug Fix – p36791812_1926000DBRU_Linux-x86-64.zip
- Recommended one of patch – p34672698_1922000DBRU_Linux-x86-64.zip
- Recommended one of patch – p37822691_1926000DBRU_Linux-x86-64.zip
To begin and finish the patching process, simply run the main playbook. It will complete all necessary steps with a single command:
[ansible@blt01 ansible]$ ansible-playbook -i hosts projects/dbru/apply_db_update_main.yml
[ansible@blt01 ansible]$ cat projects/dbru/apply_db_update_main.yml
- name: Import playbook to prepare new Oracle Database Home
ansible.builtin.import_playbook: prepare_dbru.yml
- name: Import playbook to apply Oracle Oracle Database Release Update
ansible.builtin.import_playbook: apply_dbru_onfirstnode.yml
- name: Import playbook to run root.sh in new Oracle Database Homes
ansible.builtin.import_playbook: apply_dbru_runrootallnodes.yml
- name: Import playbook to finish Oracle Database Release Update
ansible.builtin.import_playbook: finish_dbru_onallnodes.yml
- name: Import playbook to apply Datapatch on Primary Databases
ansible.builtin.import_playbook: apply_datapatch_onprimary.yml
- name: Import playbook to Remove Old DB Home
ansible.builtin.import_playbook: remove_dbru_onallnodes.yml
Playbook contents:
Prepare Step – prepare_dbru_allnodes.yml
- name: Configure New Oracle Database Homes
hosts: dbservers
remote_user: oracle
vars:
new_db_home: /u01/app/oracle/product/19.26/dbhome_1
patch_dir: /u01/app/Setup
tasks:
- name: Prepare patch directory for setup files
ansible.builtin.file:
path: "{{ patch_dir }}"
state: directory
owner: oracle
group: oinstall
- name: Prepare new database home
ansible.builtin.file:
path: "{{ new_db_home }}"
state: directory
owner: oracle
group: oinstall
Apply Database Release Update using Out of Place Patching – apply_dbru_onfirstnode.yml
- name: Apply Oracle Database Release Update
hosts: dbservers
vars:
u01_size_mb: 13356
new_db_home: /u01/app/oracle/product/19.26/dbhome_1
old_db_home: /u01/app/oracle/product/19.24/dbhome_1
grid_home: /u01/app/19.26/grid
patch_dir: /u01/app/Setup
source_patch_dir: /u01/app/Setup
remote_user: oracle
run_once: true
tasks:
- name: Copy setup files to target server
ansible.builtin.copy:
src: "{{ source_patch_dir }}/"
dest: "{{ patch_dir }}/"
owner: oracle
group: oinstall
- name: Unzip new DB_HOME
ansible.builtin.unarchive:
src: "{{ patch_dir }}/LINUX.X64_193000_db_home.zip"
dest: "{{ new_db_home }}"
remote_src: yes
- name: Unzip OPatch to new DB_HOME
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p6880880_122010_Linux-x86-64.zip"
dest: "{{ new_db_home }}"
remote_src: yes
- name: Prepare patches directories
ansible.builtin.file:
path: "{{ item }}"
state: directory
owner: oracle
group: oinstall
loop:
- "{{ patch_dir }}/GIRU"
- "{{ patch_dir }}/OJVM"
- "{{ patch_dir }}/DBRUOneOff"
- "{{ patch_dir }}/GIMRP"
- name: unzip GIRU system patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37257886_190000_Linux-x86-64.zip"
dest: "{{ patch_dir }}/GIRU"
remote_src: yes
- name: Unzip OJVM patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37102264_190000_Linux-x86-64.zip"
dest: "{{ patch_dir }}/OJVM"
remote_src: yes
- name: unzip GIMRP
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37769929_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/GIMRP"
remote_src: yes
- name: unzip DBRU oneoff patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p34672698_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/DBRUOneOff"
remote_src: yes
- name: unzip Data Pump Bundle patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37470729_1926000DBRU_Generic.zip"
dest: "{{ patch_dir }}/DBRUOneOff"
remote_src: yes
- name: unzip Spatial Bundle patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37641238_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/DBRUOneOff"
remote_src: yes
- name: unzip FBDA OneOff patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p36791812_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/DBRUOneOff"
remote_src: yes
- name: unzip OneOff Merge patch
ansible.builtin.unarchive:
src: "{{ patch_dir }}/p37822691_1926000DBRU_Linux-x86-64.zip"
dest: "{{ patch_dir }}/DBRUOneOff"
remote_src: yes
- name: Register cluster nodes for response file
ansible.builtin.shell:
cmd: "{{ grid_home }}/bin/olsnodes | tr '\n' ',' | sed 's/,$//'"
register: cluster_nodes
- name: Register osdba value for response file
ansible.builtin.shell:
cmd: "grep 'OSDBA_GROUP=' {{ old_db_home }}/install/response/db_20*.rsp"
register: osdba
- name: Register osoper value for response file
ansible.builtin.shell:
cmd: "grep 'OSOPER_GROUP=' {{ old_db_home }}/install/response/db_20*.rsp"
register: osoper
- name: Register osbackupdba value for response file
ansible.builtin.shell:
cmd: "grep 'OSBACKUPDBA_GROUP=' {{ old_db_home }}/install/response/db_20*.rsp"
register: osbackupdba
- name: Register osdgdba value for response file
ansible.builtin.shell:
cmd: "grep 'OSDGDBA_GROUP=' {{ old_db_home }}/install/response/db_20*.rsp"
register: osdgdba
- name: Register oskmdba value for response file
ansible.builtin.shell:
cmd: "grep 'OSKMDBA_GROUP=' {{ old_db_home }}/install/response/db_20*.rsp"
register: oskmdba
- name: Register osracdba value for response file
ansible.builtin.shell:
cmd: "grep 'OSRACDBA_GROUP=' {{ old_db_home }}/install/response/db_20*.rsp"
register: osracdba
- name: Create contents of response file
ansible.builtin.copy:
dest: "{{ patch_dir }}/db_oop.rsp"
content: |
oracle.install.responseFileVersion=/oracle/install/rspfmt_dbinstall_response_schema_v19.0.0
oracle.install.option=INSTALL_DB_SWONLY
UNIX_GROUP_NAME=oinstall
INVENTORY_LOCATION=/u01/app/oraInventory
ORACLE_BASE=/u01/app/oracle
ORACLE_HOME={{ new_db_home }}
oracle.install.db.InstallEdition=EE
{{ osdba.stdout }}
{{ osoper.stdout }}
{{ osbackupdba.stdout }}
{{ osdgdba.stdout }}
{{ oskmdba.stdout }}
{{ osracdba.stdout }}
oracle.install.db.CLUSTER_NODES={{ cluster_nodes.stdout }}
SECURITY_UPDATES_VIA_MYORACLESUPPORT=false
DECLINE_SECURITY_UPDATES=true
- name: Clean up DB home zip files
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- "{{ patch_dir }}/LINUX.X64_193000_db_home.zip"
- "{{ patch_dir }}/p37257886_190000_Linux-x86-64.zip"
- "{{ patch_dir }}/p37769929_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p37102264_190000_Linux-x86-64.zip"
- "{{ patch_dir }}/p34672698_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p37470729_1926000DBRU_Generic.zip"
- "{{ patch_dir }}/p37641238_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p36791812_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p37822691_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/p6880880_122010_Linux-x86-64.zip"
- "{{ patch_dir }}/p37669540_1926000DBRU_Linux-x86-64.zip"
- "{{ patch_dir }}/LINUX.X64_193000_grid_home.zip"
- name: Check u01 free disk space
ansible.builtin.shell:
cmd: "df -P /u01 | awk 'END { print $4 }'"
register: u01size
failed_when: u01size.stdout|int < u01_size_mb * 1024
- name: Apply DBRU and one-offs
ansible.builtin.shell:
cmd: |
{{ new_db_home }}/runInstaller -silent -ignorePrereqFailure -waitforcompletion \
-applyRU {{ patch_dir }}/GIRU/37257886 \
-applyOneOffs \
{{ patch_dir }}/OJVM/37102264,{{ patch_dir }}/GIMRP/37769929/34814223,{{ patch_dir }}/GIMRP/37769929/36124707,{{ patch_dir }}/GIMRP/37769929/36534155,{{ patch_dir }}/GIMRP/37769929/36813092,{{ patch_dir }}/GIMRP/37769929/37327819,{{ patch_dir }}/GIMRP/37769929/37389579,{{ patch_dir }}/GIMRP/37769929/37421153,{{ patch_dir }}/GIMRP/37769929/37484617,{{ patch_dir }}/GIMRP/37769929/37547467,{{ patch_dir }}/GIMRP/37769929/37617711,{{ patch_dir }}/GIMRP/37769929/37621741,{{ patch_dir }}/GIMRP/37769929/37665089,{{ patch_dir }}/GIMRP/37769929/37751023,{{ patch_dir }}/GIMRP/37769929/37769636,{{ patch_dir }}/GIMRP/37769929/37792660,{{ patch_dir }}/GIMRP/37769929/37798609,{{ patch_dir }}/DBRUOneOff/34672698,{{ patch_dir }}/DBRUOneOff/36791812,{{ patch_dir }}/DBRUOneOff/37470729,{{ patch_dir }}/DBRUOneOff/37641238,{{ patch_dir }}/DBRUOneOff/37822691 \
-responsefile {{ patch_dir }}/db_oop.rsp
environment:
CV_ASSUME_DISTID: OL7
NEWDBHOME: "{{ new_db_home }}"
register: apply_dbru
failed_when: "'Successfully Setup Software' not in apply_dbru.stdout"
async: 7200
poll: 20
- name: Output patching success message
ansible.builtin.debug:
msg: "Patching succeeded. InsaneDBA was here."
when: apply_dbru.rc in [6,0]
Run root.sh step – apply_dbru_runrootallnodes.yml
- name: Run root.sh in the new Oracle database home
hosts: dbservers
vars:
new_db_home: /u01/app/oracle/product/19.26/dbhome_1
old_db_home: /u01/app/oracle/product/19.24/dbhome_1
remote_user: root
tasks:
- name: Execute root.sh
ansible.builtin.command:
cmd: "{{ new_db_home }}/root.sh"
throttle: 1
- name: Replace old_dbhome value in .bashrc files with the new_dbhome value
ansible.builtin.replace:
path: "{{ item }}"
regexp: "{{ old_db_home }}"
replace: "{{ new_db_home }}"
loop:
- /root/.bashrc
- /home/oracle/.bashrc
Finish Oracle Database Release Update and start databases from new database home – finish_dbru_onallnodes.yml
- name: Finish Database Release Update
hosts: dbservers
vars:
new_db_home: /u01/app/oracle/product/19.26/dbhome_1
old_db_home: /u01/app/oracle/product/19.24/dbhome_1
patch_dir: /u01/app/Setup
recovery_script_dest_dir: /home/oracle
recovery_script_dir: /etc/ansible/projects
remote_user: oracle
tasks:
- name: Remove response file from stage directory
ansible.builtin.file:
path: "{{ patch_dir }}/db_oop.rsp"
state: absent
- name: Copy old db home dependent network files to the new db home
ansible.builtin.copy:
src: "{{ old_db_home }}/network/admin/"
dest: "{{ new_db_home }}/network/admin/"
owner: oracle
group: oinstall
remote_src: yes
- name: Copy old db home dependent dbs parameter files to the new db home
ansible.builtin.copy:
src: "{{ old_db_home }}/dbs/"
dest: "{{ new_db_home }}/dbs/"
owner: oracle
group: oinstall
remote_src: yes
- name: Copy old db home dependent customized files to the new db home
ansible.builtin.copy:
src: "{{ old_db_home }}/sqlplus/admin/glogin.sql"
dest: "{{ new_db_home }}/sqlplus/admin/"
owner: oracle
group: oinstall
remote_src: yes
- name: Relink unified auditing in new_dbhome
ansible.builtin.command:
cmd: "make -f ins_rdbms.mk uniaud_on ioracle"
chdir: "{{ new_db_home }}/rdbms/lib"
environment:
ORACLE_HOME: "{{ new_db_home }}"
- name: Register databases
ansible.builtin.shell:
cmd: "ps -ef | grep ora_pmon | grep -v grep | awk '{ print $NF }' | cut -c10-50 | awk '{print substr($1, 1, length($1)-1)}'"
register: find_databases
- name: Register instances
ansible.builtin.shell:
cmd: "ps -ef | grep ora_pmon | grep -v grep | awk '{ print $NF }' | cut -c10-50"
register: find_instances
- name: Modify databases with srvctl to run from new_dbhome
ansible.builtin.command:
cmd: "srvctl modify database -d {{ item }} -oraclehome {{ new_db_home }}"
loop: "{{ find_databases.stdout_lines }}"
run_once: true
- name: Bounce instances and start from new_dbhome
ansible.builtin.shell:
cmd: |
export dbname=$(echo {{ item }} | awk '{print substr($1, 1, length($1)-1)}')
srvctl stop instance -d $dbname -i {{ item }} -f
srvctl start instance -d $dbname -i {{ item }}
loop: "{{ find_instances.stdout_lines }}"
throttle: 1
- name: Remove patch setup folders from stage directory
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- "{{ patch_dir }}/GIRU"
- "{{ patch_dir }}/DBRUOneOff"
- "{{ patch_dir }}/OJVM"
- "{{ patch_dir }}/GIMRP"
- name: Copy start recovery file to remote server
ansible.builtin.copy:
src: "{{ recovery_script_dir }}/start_recover_onremote.sh"
dest: "{{ recovery_script_dest_dir }}"
owner: oracle
group: oinstall
mode: '0750'
- name: Start recovery
ansible.builtin.command:
cmd: "{{ recovery_script_dest_dir }}/start_recover_onremote.sh {{ item }} {{ new_db_home }}"
loop: "{{ find_instances.stdout_lines }}"
register: recovery_output
- name: Debug Recovery output
ansible.builtin.debug:
var: item.stdout
loop: "{{ recovery_output.results }}"
Apply datapatch – apply_datapatch_onprimary.yml
- name: Apply Data Patch on First Nodes of Primary Databases
hosts: dbservers
vars:
new_db_home: /u01/app/oracle/product/19.26/dbhome_1
db_role: PRIMARY
remote_user: oracle
run_once: true
tasks:
- name: Register instances
ansible.builtin.shell:
cmd: ps -ef | grep ora_pmon | grep -v grep | awk '{ print $NF }' | cut -c10-50
register: find_instances
- name: Apply datapatch
ansible.builtin.shell:
cmd: |
export instname={{ item }}
export dbname=$(echo $instname | awk '{print substr($1, 1, length($1)-1)}')
export inst_id=$(echo $instname | awk '{print substr($1,length($1),1)}')
export dbrole=$(srvctl config database -d $dbname | grep "Database role" | awk '{ print $NF }')
if [ "$inst_id" == 1 ] && [ "$dbrole" == "{{ db_role }}" ]; then
export ORACLE_HOME={{ new_db_home }}
export ORACLE_SID=$instname
$ORACLE_HOME/OPatch/datapatch -verbose
fi
register: datapatch_candidates
loop: "{{ find_instances.stdout_lines }}"
throttle: 1
- name: Debug datapatch output
ansible.builtin.debug:
var: item.stdout
loop: "{{ datapatch_candidates.results }}"
Optional : Remove Old Database Home – remove_dbru_onallnodes.yml
- name: Deinstall old Oracle Database Software and remove old oracle database home
hosts: all
vars:
old_db_home: /u01/app/oracle/product/19.24/dbhome_1
patch_dir: /u01/app/Setup
ansible_python_interpreter: /usr/bin/python3
removed_value: REMOVED="T"/>
remote_user: root
tasks:
- name: Deinstall old_dbhome
become: yes
become_user: oracle
become_method: su
ansible.builtin.expect:
command: /bin/bash -c {{ old_db_home }}/deinstall/deinstall
responses:
'Do you want to continue': 'y'
'Specify the list of database names': ''
echo: yes
timeout: 600
run_once: true
register: deinstall_result
- name: Check inventory whether old_dbhome is tagged with removed flag
ansible.builtin.shell:
cmd: "grep '{{ old_db_home }}' /u01/app/oraInventory/ContentsXML/inventory.xml | awk '{ print $NF }'"
register: removedflag
- name: Remove parent directory of old_db_home
ansible.builtin.file:
path: "{{ old_db_home | dirname }}"
state: absent
environment:
OLDDBHOME: "{{ old_db_home }}"
when: deinstall_result.rc == 0 or removedflag.stdout == removed_value
Content of the start_recover_onremote.sh
#!/bin/bash
export ORACLE_SID=$1
export ORACLE_HOME=$2
$ORACLE_HOME/bin/sqlplus -s /nolog << END_SQL
conn / as sysdba
set serveroutput on feedback off;
DECLARE
inst_id number;
mrp number;
inst_name varchar2(50);
BEGIN
IF sys_context ('userenv','database_role') = 'PHYSICAL STANDBY'
THEN
select instance_number, instance_name into inst_id, inst_name from v\$instance ;
select count(*) into mrp from v\$managed_standby where process='MRP0';
if inst_id = 1 and mrp = 0
THEN
execute immediate 'ALTER DATABASE RECOVER MANAGED STANDBY DATABASE DISCONNECT';
dbms_output.put_line('Recovery started on: ' || inst_name);
ELSE
dbms_output.put_line('No action taken. ');
END IF;
ELSE
dbms_output.put_line('No action taken. ');
END IF;
END;
/
exit;
END_SQL
Contribute or Comment
Feel free to fork, suggest improvements, or just drop a comment. I keep the repo up to date with each RU and always enjoy feedback from fellow DBAs.
Hope it helps your patching process.


Leave your comment