2026-06-28 12:00:23 +02:00
---
# Playbook: ora_stand_datapatch.yml
# Usage example:
# ansible-playbook playbooks/ora_stand_datapatch.yml \
# -e server=togoria \
# -e oracle_sid=NABOOPRD
- name : Gather facts for a specific inventory host
hosts : "{{ server }}"
gather_facts : yes
become : true
become_user : oracle
become_method : su
pre_tasks :
- name : Ensure 'server' variable is provided
assert :
that : server is defined
fail_msg : "Please provide the server via -e 'server=<server>'"
- name : Ensure 'oracle_sid' variable is provided
assert :
that : oracle_sid is defined
fail_msg : "Please provide the oracle_sid via -e 'oracle_sid=<oracle_sid>'"
tasks :
- name : Show selected system facts
debug :
msg :
hostname : "{{ (ansible_facts.nodename | default(ansible_facts.hostname)) | default('unknown') }}"
os_family : "{{ ansible_facts.os_family | default(ansible_facts.distribution | default('unknown')) }}"
operating_system : "{{ ansible_facts.distribution | default('unknown') }} {{ ansible_facts.distribution_version | default('') }}"
ip_address : "{{ ansible_default_ipv4.address | default('unknown') }}"
hardware_model : "{{ ansible_facts['machine'] | default('unknown') }}"
cpu_count : "{{ ansible_facts['processor_vcpus'] | default(ansible_facts['processor_count'] | default('unknown')) }}"
ram_gb : "{{ (ansible_facts['memtotal_mb'] / 1024) | int | default('unknown') }}"
- name : Source oraenv and display OPatch informations
shell : |
. oraenv <<< {{ oracle_sid }} && $ORACLE_HOME/OPatch/opatch version && echo && echo && $ORACLE_HOME/OPatch/opatch lspatches
register : opatch_output
when : oracle_sid is defined
- name : Display OPatch output
debug :
var : opatch_output.stdout_lines
when : oracle_sid is defined
- name : Check Oracle instance status via sqlplus as SYSDBA
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
set heading off feedback off verify off pagesize 0
select status from v$instance;
exit
SQL
register : instance_status
changed_when : false
when : oracle_sid is defined
- name : Show Oracle instance status
debug :
msg : "Oracle instance {{ oracle_sid }} status: {{ instance_status.stdout | trim | default('unknown') }}"
when : oracle_sid is defined
- name : Fail if Oracle instance is not OPEN
fail :
msg : "Oracle instance {{ oracle_sid }} is not OPEN (status: {{ instance_status.stdout | default('unknown') }})"
when : oracle_sid is defined and ("OPEN" not in (instance_status.stdout | default('')))
- name : List PDBs (if multitenant)
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
set heading off feedback off verify off pagesize 0
2026-06-28 21:28:40 +02:00
select name||':'||open_mode||':'||restricted from v$pdbs where name!='PDB$SEED';
2026-06-28 12:00:23 +02:00
exit
SQL
register : pdb_list
failed_when : false
changed_when : false
when : oracle_sid is defined
- name : Determine if database is multitenant
set_fact :
is_multitenant : "{{ (pdb_list.stdout is defined) and ('ORA-' not in pdb_list.stdout) and (pdb_list.stdout | trim != '') }}"
when : oracle_sid is defined
- name : Show PDB list (if multitenant)
debug :
2026-06-28 21:28:40 +02:00
msg : |
PDB, OPEN, RESTRICTED
{% for pdb in pdb_list.stdout_lines %}
{{ pdb }}
{% endfor %}
2026-06-28 12:00:23 +02:00
when : oracle_sid is defined and is_multitenant
2026-06-28 21:28:40 +02:00
- name : Check for non-OPEN PDBs or RESTRICTED PDBs
2026-06-28 12:00:23 +02:00
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
set heading off feedback off verify off pagesize 0
2026-06-28 21:28:40 +02:00
select name||':'||open_mode||':'||restricted from v$pdbs where name!='PDB$SEED' and (upper(open_mode) not like '%READ WRITE%' or upper(restricted) = 'YES');
2026-06-28 12:00:23 +02:00
exit
SQL
register : pdb_not_open
failed_when : false
changed_when : false
when : oracle_sid is defined and is_multitenant
- name : Filter non-empty PDB results
set_fact :
pdb_not_open_filtered : "{{ pdb_not_open.stdout_lines | select('match', '^.+:.+$') | list }}"
when : oracle_sid is defined and is_multitenant
- name : Fail if any PDB is not OPEN
fail :
msg : "PDB(s) not OPEN: {{ pdb_not_open_filtered }}"
when : oracle_sid is defined and is_multitenant and (pdb_not_open_filtered | length) > 0
2026-06-28 21:28:40 +02:00
- name : Execute datapatch
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/OPatch/datapatch
register : datapatch_output
changed_when : false
when : oracle_sid is defined
- name : Show datapatch output
debug :
var : datapatch_output.stdout_lines
when : oracle_sid is defined
- name : Remove temporary SQL files from remote host
file :
path : "{{ item }}"
state : absent
loop :
- /tmp/dba_invalid_objects.sql
- /tmp/dba_registry.sql
when : oracle_sid is defined
- name : Execute utlrp.sql in CDB$ROOT
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
@$ORACLE_HOME/rdbms/admin/utlrp.sql
exit
SQL
register : utlrp_root
changed_when : false
when : oracle_sid is defined
- name : Get list of PDBs for utlrp execution
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
set heading off feedback off verify off pagesize 0
select name from v$pdbs where name!='PDB$SEED' and open_mode like '%READ WRITE%' and restricted='NO';
exit
SQL
register : pdb_names
failed_when : false
changed_when : false
when : oracle_sid is defined and is_multitenant
- name : Execute utlrp.sql in each PDB
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
alter session set container={{ item | trim }};
@$ORACLE_HOME/rdbms/admin/utlrp.sql
exit
SQL
loop : "{{ pdb_names.stdout_lines | default([]) }}"
loop_control :
label : "{{ item }}"
register : utlrp_pdb_results
changed_when : false
failed_when : false
when : oracle_sid is defined and is_multitenant and (pdb_names.stdout_lines | default([]) | length) > 0
- name : Copy dba_invalid_objects.sql to remote host
copy :
src : ../files/scripts/sql/dba_invalid_objects.sql
dest : /tmp/dba_invalid_objects.sql
mode : '0644'
when : oracle_sid is defined
- name : Copy dba_registry.sql to remote host
copy :
src : ../files/scripts/sql/dba_registry.sql
dest : /tmp/dba_registry.sql
mode : '0644'
when : oracle_sid is defined
- name : Execute dba_invalid_objects.sql in CDB$ROOT
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
@/tmp/dba_invalid_objects.sql
exit
SQL
register : dba_invalid_root
changed_when : false
when : oracle_sid is defined
- name : Show dba_invalid_objects.sql results in CDB$ROOT
debug :
var : dba_invalid_root.stdout_lines
when : oracle_sid is defined
- name : Execute dba_registry.sql in CDB$ROOT
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
@/tmp/dba_registry.sql
exit
SQL
register : dba_registry_root
changed_when : false
when : oracle_sid is defined
- name : Show dba_registry.sql results in CDB$ROOT
debug :
var : dba_registry_root.stdout_lines
when : oracle_sid is defined
- name : Execute dba_invalid_objects.sql in each PDB
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
alter session set container={{ item | trim }};
@/tmp/dba_invalid_objects.sql
exit
SQL
loop : "{{ pdb_names.stdout_lines | default([]) }}"
loop_control :
label : "{{ item }}"
register : dba_invalid_pdb_results
changed_when : false
failed_when : false
when : oracle_sid is defined and is_multitenant and (pdb_names.stdout_lines | default([]) | length) > 0
- name : Show dba_invalid_objects.sql results in PDBs
debug :
msg : |
dba_invalid_objects.sql output for PDB: {{ item }}
{{ dba_invalid_pdb_results.results[pdb_names.stdout_lines.index(item)].stdout }}
loop : "{{ pdb_names.stdout_lines | default([]) }}"
loop_control :
label : "{{ item }}"
when : oracle_sid is defined and is_multitenant and (pdb_names.stdout_lines | default([]) | length) > 0
- name : Execute dba_registry.sql in each PDB
shell : |
. oraenv <<< {{ oracle_sid }} >/dev/null 2>&1
$ORACLE_HOME/bin/sqlplus -s / as sysdba <<'SQL'
alter session set container={{ item | trim }};
@/tmp/dba_registry.sql
exit
SQL
loop : "{{ pdb_names.stdout_lines | default([]) }}"
loop_control :
label : "{{ item }}"
register : dba_registry_pdb_results
changed_when : false
failed_when : false
when : oracle_sid is defined and is_multitenant and (pdb_names.stdout_lines | default([]) | length) > 0
- name : Show dba_registry.sql results in PDBs
debug :
msg : |
dba_registry.sql output for PDB: {{ item }}
{{ dba_registry_pdb_results.results[pdb_names.stdout_lines.index(item)].stdout }}
loop : "{{ pdb_names.stdout_lines | default([]) }}"
loop_control :
label : "{{ item }}"
when : oracle_sid is defined and is_multitenant and (pdb_names.stdout_lines | default([]) | length) > 0
- name : Remove temporary SQL files from remote host
file :
path : "{{ item }}"
state : absent
loop :
- /tmp/dba_invalid_objects.sql
- /tmp/dba_registry.sql
when : oracle_sid is defined