refresh pdb - liamlamth/blog GitHub Wiki
repeatedly clone pdb and make customized modification, such as production environment mirror
-
dictionary/log
select * from dba_scheduler_chains; select * from dba_scheduler_chain_steps; select * from dba_scheduler_chain_rules; select * from dba_db_links; select * from dba_scheduler_job_run_details where job_name = 'JOB_REFRESH_PDB' order by 1 desc; select * from refresh_log; select * from refresh_log_last;
-
cleaning existing built
exec DBMS_SCHEDULER.PURGE_LOG(); begin DBMS_SCHEDULER.stop_job ('JOB_REFRESH_PDB'); end; / begin DBMS_SCHEDULER.drop_job ('JOB_REFRESH_PDB'); DBMS_SCHEDULER.drop_chain ('CHAIN_REFRESH_PDB', true); DBMS_SCHEDULER.drop_program ('PGM_CLONE_PDB'); DBMS_SCHEDULER.drop_program ('PGM_CLEANSE_P_UAT'); DBMS_SCHEDULER.drop_program ('PGM_SUMMARIZE_CLONE'); end; / -
create chain and job
create or replace procedure refresh_pdb(in_src_cdb in varchar2, in_src_pdb in varchar2, in_loc_pdb in varchar2) is v_common_location varchar2(100) := '/u02/oradata/'; v_lcdb_name varchar2(10); v_lpdb_status varchar2(10); v_job_duration varchar2(10); stop_job exception; err_msg varchar2(200); begin /* PREREQUISITE: - assume datafile located in same parent directory name (v_common_location) - source cdb: archivelog mode (select log_mode from v$database;) - source cdb: clone user (CREATE USER c##cloner IDENTIFIED BY ABCD1234 CONTAINER=ALL; GRANT CREATE SESSION, CREATE PLUGGABLE DATABASE TO c##cloner CONTAINER=ALL;) - local server: add source db entry in tnsname.ora - local cdb: create database link TWCDB connect to c##cloner identified by ABCD1234 using 'TWCDB'; REQUIRED LOG TABLE : create table REFRESH_LOG (LOG_ID number generated by default on null as identity, LOG_TIME timestamp default systimestamp, LOG_TYPE varchar2(20), DESCRIPTION varchar2(200) ); OPTIONAL VIEW: create or replace view refresh_log_last as select * from refresh_log where log_id >= (select max(log_id) from refresh_log where log_type = 'summary' and description = 'begin refresh') order by log_id; */ insert into refresh_log(log_type,description) values('summary','begin refresh'); execute immediate 'select 1 from user_tables@'||in_src_cdb; select name into v_lcdb_name from v$database; select (select open_mode from v$pdbs where name = in_loc_pdb) into v_lpdb_status from dual; if v_lpdb_status in ('READ WRITE','READ ONLY') then insert into refresh_log(log_type,description) values('details','target pdb is open'); elsif v_lpdb_status in ('MOUNTED') then insert into refresh_log(log_type,description) values('details','target pdb is close.'); goto drop_pdb; elsif v_lpdb_status is null then insert into refresh_log(log_type,description) values('details','target pdb does not exist.'); goto clone_pdb; else insert into refresh_log(log_type,description) values('details','target pdb abnormal'); raise stop_job; end if; insert into refresh_log(log_type,description) values('details','shutting down the old target pdb...'); execute immediate 'alter pluggable database '||in_loc_pdb||' close immediate'; <<drop_pdb>> insert into refresh_log(log_type,description) values('details','droping the old target pdb...'); execute immediate 'drop pluggable database '||in_loc_pdb||' including datafiles'; <<clone_pdb>> insert into refresh_log(log_type,description) values('details','cloning the source pdb...'); execute immediate 'create pluggable database '||in_loc_pdb||' from '||in_src_pdb||'@'||in_src_cdb|| ' file_name_convert = ('''||v_common_location||in_src_cdb||'/'||in_src_pdb||''','''||v_common_location||v_lcdb_name||'/'||in_loc_pdb||''')'; insert into refresh_log(log_type,description) values('details','starting the fresh target pdb...'); execute immediate 'alter pluggable database '||in_loc_pdb||' open'; select (select open_mode from v$pdbs where name = in_loc_pdb) into v_lpdb_status from dual; if v_lpdb_status = 'READ WRITE' then select case extract(day from diff) when 0 then lpad(extract(hour from diff),2,'0') || ':' || lpad(extract(minute from diff),2,'0') || ':' || lpad(ceil(extract(second from diff)),2,'0') else '1 day+' end into v_job_duration from (select systimestamp-log_time diff from refresh_log where log_id = (select max(log_id) from refresh_log where log_type = 'summary' and description = 'begin refresh') ); insert into refresh_log(log_type,description) values('duration',v_job_duration); insert into refresh_log(log_type,description) values('summary','succeed refresh'); else insert into refresh_log(log_type,description) values('summary','failed refresh'); end if; commit; exception when stop_job then insert into refresh_log(log_type,description) values('summary','cancelled refresh'); commit; when others then err_msg := substr(sqlerrm, 1, 200); insert into refresh_log(log_type,description) values('summary', err_msg ); insert into refresh_log(log_type,description) values('summary','cancelled refresh'); commit; end;DECLARE l_plsql_clone varchar2(32767); l_script_cleanse varchar2(32767); l_script_summarize varchar2(32767); BEGIN l_plsql_clone := ' BEGIN REFRESH_PDB(''C_PROD'',''P_PROD'',''P_UAT''); END;'; l_script_cleanse := ' /* customized after-clone script */ conn / as sysdba col c_today new_value v_today select to_char(sysdate,''YYYYMMDD'') as c_today from dual; spool /log/cleanse_p_uat_'||chr(38)||'v_today..log set lin 230 col LOG_TIME format a30 col LOG_TYPE format a10 col DESCRIPTION format a50 select * from refresh_log_last ; conn appdba/apppassword@P_UAT as sysdba commit; '; l_script_summarize := ' #!/usr/bin/ksh if [ $(/usr/bin/grep -ic "ERROR\|ORA-\|FAIL" /log/cleanse_p_uat_$(date ''+%Y%m%d'').log) -gt 0 ]; then cat /log/cleanse_$(date ''+%Y%m%d'').log | /usr/bin/mutt -s "P_UAT ERROR: Cloning Job - $(date ''+%Y-%m-%d'')" -- db_adm fi '; DBMS_SCHEDULER.CREATE_PROGRAM ( program_name => 'PGM_CLONE_PDB', program_type => 'PLSQL_BLOCK', program_action => l_plsql_clone, enabled => TRUE); DBMS_SCHEDULER.CREATE_PROGRAM ( program_name => 'PGM_CLEANSE_P_UAT', program_type => 'SQL_SCRIPT', program_action => l_script_cleanse, enabled => TRUE); DBMS_SCHEDULER.CREATE_PROGRAM ( program_name => 'PGM_SUMMARIZE_CLONE', program_type => 'EXTERNAL_SCRIPT', program_action => l_script_summarize, enabled => TRUE); END; /BEGIN DBMS_SCHEDULER.CREATE_CHAIN ( chain_name => 'CHAIN_REFRESH_PDB'); DBMS_SCHEDULER.DEFINE_CHAIN_STEP ( chain_name => 'CHAIN_REFRESH_PDB', -- this must be the same name you used in the chain object definition / creation step_name => 'CLONE_PDB', program_name => 'PGM_CLONE_PDB'); DBMS_SCHEDULER.DEFINE_CHAIN_STEP ( chain_name => 'CHAIN_REFRESH_PDB', -- this must be the same name you used in the chain object definition / creation step_name => 'CLEANSE_P_UAT', program_name => 'PGM_CLEANSE_P_UAT'); DBMS_SCHEDULER.DEFINE_CHAIN_STEP ( chain_name => 'CHAIN_REFRESH_PDB', -- this must be the same name you used in the chain object definition / creation step_name => 'SUMMARIZE_CLONE', program_name => 'PGM_SUMMARIZE_CLONE'); DBMS_SCHEDULER.ENABLE ('CHAIN_REFRESH_PDB'); DBMS_SCHEDULER.ALTER_CHAIN('CHAIN_REFRESH_PDB','CLEANSE_P_UAT','credential_name','ORACLE'); DBMS_SCHEDULER.ALTER_CHAIN('CHAIN_REFRESH_PDB','SUMMARIZE_CLONE','credential_name','ORACLE'); DBMS_SCHEDULER.DEFINE_CHAIN_RULE ( chain_name => 'CHAIN_REFRESH_PDB', condition => 'TRUE', action => 'START CLONE_PDB', rule_name => 'CHAIN_REFRESH_PDB_RULE_1'); DBMS_SCHEDULER.DEFINE_CHAIN_RULE ( chain_name => 'CHAIN_REFRESH_PDB', condition => 'CLONE_PDB SUCCEEDED', action => 'START CLEANSE_P_UAT', rule_name => 'CHAIN_REFRESH_PDB_RULE_2'); DBMS_SCHEDULER.DEFINE_CHAIN_RULE ( chain_name => 'CHAIN_REFRESH_PDB', condition => 'CLEANSE_P_UAT SUCCEEDED', action => 'START SUMMARIZE_CLONE', rule_name => 'CHAIN_REFRESH_PDB_RULE_3'); DBMS_SCHEDULER.DEFINE_CHAIN_RULE ( chain_name => 'CHAIN_REFRESH_PDB', condition => 'SUMMARIZE_CLONE SUCCEEDED', action => 'END', rule_name => 'CHAIN_REFRESH_PDB_RULE_4'); DBMS_SCHEDULER.CREATE_JOB ( job_name => 'JOB_REFRESH_PDB', job_type => 'CHAIN', job_action => 'CHAIN_REFRESH_PDB', repeat_interval => 'freq=daily; byhour=0; byminute=0', enabled => TRUE); END; /