Oracle EBS database hooks in OCI ExaCC or ExaCS

Oracle OCI cloud does not allow ORACLE_HOME(DBTechStack) provisioning on NFS mount. ORACLE_HOME is created using OCI console or CLI. In ExaCS or ExaCC, Delphix relinquishes the responsibility to manage the life cycle of ORACLE_HOME to Enduser. This brings one caveat that the hooks utility feature will not be present during the vPDB/vCDB provision.
To overcome this, Use the following hooks:

  1. To complete the DB Provisioning operation, you must provide content to configure clones and pre-snapshot hooks.  You must set a hooks environment variable DLPX_SOURCE_APPS_PASSWORD to provide the source apps schema password and DLPX_SYS_PASSWORD for the SYSTEM schema password. 

  2. Pre-Snapshot hook: You must set a hooks environment variable DLPX_SOURCE_APPS_PASSWORD for providing the source apps schema password. In case the apps password change is required in the target VDB, you can set hook environment variables DLPX_TARGET_APPS_PASSWORD for providing the target apps schema. 

  3. Add a Run Bash Shell Command operation to the Configure Clone hook to ensure that adcfgclone utility is run against the newly provisioned database for a high privileged user, as shown in the script below. 

  4. You can pass the credentials securely to Hook Operations by setting up the base variables. See Other hook operations for more details. 

Note: It is mandatory to set a hooks environment variable DLPX_SOURCE_APPS_PASSWORD for providing the source apps schema password.  In case the apps password change is required in target VDB, you can set hook environment variables DLPX_TARGET_APPS_PASSWORD, and DLPX_SYS_PASSWORD for providing the target apps schema and system schema passwords in respective hooks. The variables will be declared in the Credential Environment Variables hook section. You can pass the credentials securely to Hook Operations by setting up the base variables. See Other hook operations for more details. 

  1. The hooks environment variable will be declared as, DLPX_SOURCE_APPS_PASSWORD and then its password value will be the same variable used in hooks, along with the PASSWORD keyword appended at the end so that it will be like DLPX_SOURCE_APPS_PASSWORD_PASSWORD.
    We assign the value of $DLPX_SOURCE_APPS_PASSWRD to APPS_PASSWD. In hooks, it is written as follows:

    APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
  2. for SYSTEM_PASSWD: 

    SYSTEM_PASSWD=$DLPX_SYS_PASSWORD_PASSWORD 

Note: Customers must identify the DLPX_DB_EXEC_SCRIPT value from their remote environment, this would always be inside the toolkit directory provided while adding the environment on Delphix Continuous Data Engine. You should replace the value for DLPX_DB_EXEC_SCRIPT from all the given hooks according to the path that exists in your environment. Please replace the following lines from hook scripts accordingly. You can pass the credentials securely to Hook Operations by setting up the base variables. See Other hook operations for more details. 

  1. Run these scripts:

    DLPX_DB_EXEC_SCRIPT="<Remote BIN location till dlpx_db_exec script>" 
    DLPX_PRIV_USER=<replace with your database user> e.g:oravis
  2. Configure clone first hook for a 19c multi-tenant high-privileged user.

    #!/usr/bin/env bash 
    # Copyright (c) 2022 by Delphix. All rights reserved. 
    # shellcheck source=/dev/null 
    # NOTE: Ensure the below environment variables will be set up correctly by the 
    # shell. If not, hardcode or generate the values below. 
    HOSTNAME=$(uname -n | cut -d '.' -f1) 
    CONTEXT_NAME=${DELPHIX_PDB_NAME}_${HOSTNAME} 
    APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
    . "${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env"; 
    # Check for local_listener parameter is set for PDB, otherwise set it 
    # appropriately 
    check_value=$(sqlplus -s "/ as sysdba" <<EOF 
    alter session set container="${DELPHIX_PDB_NAME}"; 
    show parameter local_listener; 
    EOF 
    ) 
    local_listener=$(echo "$check_value" | awk '{print $11}') 
    value=("${local_listener//:/ }") 
    host="${value[0]}" 
    port="${value[1]}" 
    curr_port=$(grep PORT < "${ORACLE_HOME}/network/admin/listener.ora" | awk '{print $9}' | sed 's/)//g') 
    if [[ $port != "$curr_port" || $host != "${HOSTNAME}" ]]; then 
    sqlplus -s "/ as sysdba" <<EOF 
    alter session set container="${DELPHIX_PDB_NAME}"; 
    alter system set local_listener='${HOSTNAME}:${curr_port}'; 
    alter system register; 
    EOF 
    fi 
    #For compatibility with 6.0.16.0 Delphix Continuous Data Engine version 
    . ${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env; sqlplus -s "/ as sysdba" <<EOF 
    shutdown immediate; 
    startup; 
    ALTER PLUGGABLE DATABASE ALL OPEN read write services=all; 
    alter pluggable database ${DELPHIX_PDB_NAME} open read write services=all; 
    alter pluggable database all save state instances=all; 
    EOF 
    sqlplus "/ as sysdba" <<EOF 
    @${ORACLE_HOME}/appsutil/install/${CONTEXT_NAME}/adupdlib.sql so 
    EOF 
    . "${ORACLE_HOME}/${CONTEXT_NAME}.env"; 
    perl "${ORACLE_HOME}/appsutil/clone/bin/adcfgclone.pl" dbconfig "${ORACLE_HOME}/appsutil/${CONTEXT_NAME}.xml" <<EOF # noqa 
    ${APPS_PASSWD} 
    EOF 
  3. Configure the Clone hook to ensure that adcfgclone is run against the newly provisioned database for a low-privileged user, as shown in the script below.
    Configure clone first hook for a 19c multi-tenant low-privileged user.

    #!/usr/bin/env bash 
    # 
    # Copyright (c) 2022 by Delphix. All rights reserved. 
    # 
    # shellcheck source=/dev/null 
    # NOTE: Ensure the below environment variables will be set up correctly by the 
    # shell. If not, hardcode or generate the values below. 
    DLPX_DB_EXEC_SCRIPT="<Remote BIN location till dlpx_db_exec script>" 
    DLPX_PRIV_USER=oravis 
    HOSTNAME=$(uname -n | cut -d '.' -f1) 
    APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
    CONTEXT_NAME=${DELPHIX_PDB_NAME}_${HOSTNAME} 
     
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env;" 
     
    # Check for local_listener parameter is set for PDB, otherwise set it appropriately 
    check_value=$("${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; sqlplus -s \"/ as sysdba\" <<-EOF 
    alter session set container=${DELPHIX_PDB_NAME}; 
    show parameter local_listener; 
    EOF 
    ") 
     
    local_listener=$(echo "$check_value" | awk '{print $11}') 
    value=("${local_listener//:/ }") 
    host="${value[0]}" 
    port="${value[1]}" 
     
    curr_port=$(grep PORT < "${ORACLE_HOME}/network/admin/listener.ora" | awk '{print $9}' | sed 's/)//g') 
     
    if [[ $port != "$curr_port" || $host != "${HOSTNAME}" ]]; then 
        "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env; sqlplus -s \"/ as sysdba\" <<EOF 
        alter session set container=${DELPHIX_PDB_NAME}; 
        alter system set local_listener='${HOSTNAME}:${curr_port}'; 
        alter system register; 
    EOF 
    " 
    fi 
     
    #For compatibility with 6.0.16.0 Delphix Continuous Data Engine version 
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env; sqlplus -s "/ as sysdba" <<EOF 
    shutdown immediate; 
    startup; 
    ALTER PLUGGABLE DATABASE ALL OPEN read write services=all; 
    alter pluggable database ${DELPHIX_PDB_NAME} open read write services=all; 
    alter pluggable database all save state instances=all; 
    EOF 
    " 
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env; sqlplus \"/ as sysdba\" <<-EOF 
    @${ORACLE_HOME}/appsutil/install/${CONTEXT_NAME}/adupdlib.sql so 
    EOF 
    " 
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; perl ${ORACLE_HOME}/appsutil/clone/bin/adcfgclone.pl dbconfig ${ORACLE_HOME}/appsutil/${CONTEXT_NAME}.xml <<-EOF1 
    ${APPS_PASSWD} 
    EOF1 
    " 
  4. While setting up hooks environment variables, if your environment is on R12.TXK.C.Delta.13 or later, set the DLPX_SYS_PASSWORD variable’s password as the password of the EBS_SYSTEM user, else if your environment is on R12.TXK.C.Delta.12 or earlier, set the DLPX_SYS_PASSWORD variable’s password as the password of the SYSTEM user in the below second hook script.
    This requirement is outlined in the FAQ: Oracle E-Business Suite and System Schema Migration (DocID 2758999.1)Using UTL_FILE_DIR or Database Directories for PL/SQL File I/O in Oracle E-Business Suite Releases 12.1 and 12.2 (DocID 2525754.1) found at http://docs.oracle.com

    Configure clone second hook for a 19c multi-tenant high-privileged user: 

    #!/usr/bin/env bash 
    # 
    # Copyright (c) 2022 by Delphix. All rights reserved. 
    # 
    # shellcheck source=/dev/null 
    # Set the target UTL_FILE_DIR values in the Oracle 19c database in the below 
    # variable UTL_FILE_DIR_PATH separated by commas 
    # Example UTL_FILE_DIR_PATH=/u01/oracle/VIS/temp/VISPDB,\ 
    # /u01/oracle/VIS/19.3.0/appsutil/outbound/UTL,/u01/tmp 
     
    # UTL_FILE_DIR_PATH=<provide utl_file_dir locations separated by commas> 
    # If your environment is on R12.TXK.C.Delta.13 or later, enter the password 
    # for the EBS_SYSTEM user. If your environment is on R12.TXK.C.Delta.12 or 
    # earlier, enter the password for the SYSTEM user. 
    SYSTEM_PASSWD=$DLPX_SYS_PASSWORD_PASSWORD 
    DLPX_HOSTNAME=$(uname -n | cut -d '.' -f1) 
    TIMESTAMP=$(date +%d-%m-%Y_%H-%M-%S) 
    CONTEXT_NAME=${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME} 
    APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
    DIR_OBJ_PATH="${ORACLE_HOME}/appsutil/outbound/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}" 
    checkExists() { 
    if [[ ! -f $1 ]]; then 
        echo "$1 does not exist." 
        exit 1 
    fi 
    } 
    checkExists "${ORACLE_HOME}/${CONTEXT_NAME}.env" 
    checkExists "${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl" 
    . "${ORACLE_HOME}/${CONTEXT_NAME}.env"; 
    echo "${APPS_PASSWD}" | perl "${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl" -contextfile="${ORACLE_HOME}/appsutil/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}.xml" -oraclehome="${ORACLE_HOME}" -outdir="${ORACLE_HOME}/appsutil/log" -mode=getUtlFileDir 
    checkExists "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
    cp "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt${TIMESTAMP}" 
    cat /dev/null > "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
    if [ -z "$UTL_FILE_DIR_PATH" ]; then 
        mkdir -p "${ORACLE_HOME}/appsutil/outbound/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}" 
        echo "${ORACLE_HOME}/appsutil/outbound/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}" > "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
        mkdir -p "${ORACLE_BASE}/temp/${DELPHIX_PDB_NAME}" 
        echo "${ORACLE_BASE}/temp/${DELPHIX_PDB_NAME}" >> "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
    else 
        echo "$UTL_FILE_DIR_PATH" | awk -F, '{ for (i = 1; i < NF+1; ++i ) print $i >> "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" }' 
    fi 
    { echo "${APPS_PASSWD}"; echo "${SYSTEM_PASSWD}"; } | perl "${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl" -contextfile="${ORACLE_HOME}/appsutil/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}.xml" -oraclehome="${ORACLE_HOME}" -outdir="${ORACLE_HOME}/appsutil/log" -mode=setUtlFileDir 
    { echo "${APPS_PASSWD}"; echo "${SYSTEM_PASSWD}"; echo "${DIR_OBJ_PATH}"; } | perl "${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl" -contextfile="${ORACLE_HOME}/appsutil/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}.xml" -oraclehome="${ORACLE_HOME}" -outdir="${ORACLE_HOME}/appsutil/log" -mode=createDirObject 
    echo "${APPS_PASSWD}" | perl "${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl" -contextfile="${ORACLE_HOME}/appsutil/${DELPHIX_PDB_NAME}_${DLPX_HOSTNAME}.xml" -oraclehome="${ORACLE_HOME}" -outdir="${ORACLE_HOME}/appsutil/log" -mode=syncUtlFileDir -skipautoconfig=yes 
  5. Configure Clone hook to ensure that sqlnet.ora or sqlnet_ifile.ora specify a value for SQLNET.ALLOWED_LOGON_VERSION_SERVER for a low-privileged user, as shown in the script below.
    While setting up hooks environment variables, if your environment is on R12.TXK.C.Delta.13 or later, set the DLPX_SYS_PASSWORD variable’s password as the password of the EBS_SYSTEM user, else if your environment is on R12.TXK.C.Delta.12 or earlier, set the DLPX_SYS_PASSWORD variable’s password as the password of the SYSTEM user in the below second hook script.
    This requirement is outlined in the FAQ: Oracle E-Business Suite and System Schema Migration (DocID 2758999.1)Using UTL_FILE_DIR or Database Directories for PL/SQL File I/O in Oracle E-Business Suite Releases 12.1 and 12.2 (DocID 2525754.1) found at http://docs.oracle.com.
    Configure clone second hook for a 19c multi-tenant low-privileged user.

    #!/usr/bin/env bash 
    # 
    # Copyright (c) 2022 by Delphix. All rights reserved. 
    # 
    # shellcheck source=/dev/null 
    # Set the target UTL_FILE_DIR values in the Oracle 19c database 
    # Example UTL_FILE_DIR_PATH=/u01/oracle/VIS/temp/VISPDB,\ 
    # /u01/oracle/VIS/19.3.0/appsutil/outbound/UTL 
     
    # UTL_FILE_DIR_PATH=<provide utl_file_dir locations separated by commas> 
    # If your environment is on R12.TXK.C.Delta.13 or later, enter the password 
    # for the EBS_SYSTEM user. If your environment is on R12.TXK.C.Delta.12 or 
    # earlier, enter the password for the SYSTEM user. 
    SYSTEM_PASSWD=$DLPX_SYS_PASSWORD_PASSWORD 
    DLPX_DB_EXEC_SCRIPT="<Remote BIN location till dlpx_db_exec script>" 
    DLPX_PRIV_USER=oravis 
    APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
    HOSTNAME=$(uname -n | cut -d '.' -f1) 
    CONTEXT_NAME=${DELPHIX_PDB_NAME}_${HOSTNAME} 
    DIR_OBJ_PATH="${ORACLE_HOME}/appsutil/outbound/${CONTEXT_NAME}" 
    TIMESTAMP=$(date +%d-%m-%Y_%H-%M-%S) 
    checkExists() { 
    if [[ ! -f $1 ]]; then 
        echo "$1 does not exist." 
        exit 1 
    fi 
    } 
    checkExists "${ORACLE_HOME}/${CONTEXT_NAME}.env" 
    checkExists "${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl" 
    . "${ORACLE_HOME}/${CONTEXT_NAME}.env"; 
     
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; perl ${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl -contextfile=${ORACLE_HOME}/appsutil/${CONTEXT_NAME}.xml -oraclehome=${ORACLE_HOME} -outdir=${ORACLE_HOME}/appsutil/log -mode=getUtlFileDir <<-EOF 
    ${APPS_PASSWD} 
    EOF 
    " 
     
    checkExists "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "cp ${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" "${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt${TIMESTAMP}" 
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "echo ""  > \"${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt\"" 
     
    # Initialise for shell check to succeed 
    i=0 
    if [ -z "$UTL_FILE_DIR_PATH" ]; then 
        "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "mkdir -p ${ORACLE_HOME}/appsutil/outbound/${CONTEXT_NAME}" 
        "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "echo ${ORACLE_HOME}/appsutil/outbound/${CONTEXT_NAME} > ${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
        "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "mkdir -p ${ORACLE_BASE}/temp/${DELPHIX_PDB_NAME}" 
        "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "echo ${ORACLE_BASE}/temp/${DELPHIX_PDB_NAME} >> ${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
    else 
        "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" "echo $UTL_FILE_DIR_PATH | awk -F, '{ for (i = 1; i < NF+1; ++i ) print $i }' > ${ORACLE_HOME}/dbs/${DELPHIX_PDB_NAME}_utlfiledir.txt" 
    fi 
     
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; perl ${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl -contextfile=${ORACLE_HOME}/appsutil/${CONTEXT_NAME}.xml -oraclehome=${ORACLE_HOME} -outdir=${ORACLE_HOME}/appsutil/log -mode=setUtlFileDir <<-EOF1 
    ${APPS_PASSWD} 
    ${SYSTEM_PASSWD} 
    EOF1 
    " 
     
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; perl ${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl -contextfile=${ORACLE_HOME}/appsutil/${CONTEXT_NAME}.xml -oraclehome=${ORACLE_HOME} -outdir=${ORACLE_HOME}/appsutil/log -mode=createDirObject <<-EOF2 
    ${APPS_PASSWD} 
    ${SYSTEM_PASSWD} 
    ${DIR_OBJ_PATH} 
    EOF2 
    " 
     
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; perl ${ORACLE_HOME}/appsutil/bin/txkCfgUtlfileDir.pl -contextfile=${ORACLE_HOME}/appsutil/${CONTEXT_NAME}.xml -oraclehome=${ORACLE_HOME} -outdir=${ORACLE_HOME}/appsutil/log -mode=syncUtlFileDir -skipautoconfig=yes <<-EOF3 
    ${APPS_PASSWD} 
    EOF3 
    " 
  6. Set up a Pre-Snapshot hook Run Bash Shell Command operation to run any pre-clone steps necessary and specific to your EBS database for a high privileged user, as shown in the script below.
    Normally, these steps will include running Oracle's adpreclone tool.

    Pre-snapshot hook for a 19c multi-tenant high-privileged user.

    #!/usr/bin/env bash 
    # 
    # Copyright (c) 2022 by Delphix. All rights reserved. 
    # 
    # shellcheck source=/dev/null 
    # As grep has to check all the matches in making decision on L58 
    # shellcheck disable=SC2143 
    # NOTE: Ensure the below environment variables will be set up correctly by 
    # the shell. If not, hardcode or generate the values below. 
    HOSTNAME=$(uname -n | cut -d '.' -f1) 
    CONTEXT_NAME=${DELPHIX_PDB_NAME}_${HOSTNAME} 
    SOURCE_APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
    TARGET_APPS_PASSWD=$DLPX_TARGET_APPS_PASSWORD_PASSWORD 
    timeout=3600 
    waittime=0 
    ORACLE_USER="oravis" 
     
    # Query active PDB services 
    . "${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env"; 
    check_value=$(sqlplus -s "/ as sysdba" <<EOF 
    SELECT NAME FROM v\$active_services; 
    exit; 
    EOF 
    ) 
     
    checkService() { 
    if ! echo "$1" | grep -q "$2"; then 
    . "${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env"; 
    sqlplus -s "/ as sysdba" <<EOF 
    alter session set container="${DELPHIX_PDB_NAME}"; 
    BEGIN DBMS_SERVICE.START_SERVICE( service_name => '$2'); 
    end; 
    / 
    EOF 
    fi 
    } 
     
    # Check for ebs_PDB service 
    checkService "$check_value" "ebs_${DELPHIX_PDB_NAME}" 
    # Check for PDB_ebs_patch service 
    checkService "$check_value" "${DELPHIX_PDB_NAME}_ebs_patch" 
     
    . "${ORACLE_HOME}/${CONTEXT_NAME}.env"; 
     
    testAppsPassword() { 
        local passwordInQuestion=$1 
        ERROR=$(sqlplus "apps/${passwordInQuestion}@${DELPHIX_PDB_NAME}" <<< "exit;") 
        grep ORA-01017 <<< "${ERROR}" >/dev/null && return 1 
        return 0 
    } 
     
    testAppsPassword "${SOURCE_APPS_PASSWD}" 
    testResult=$? 
     
    if [[ ${testResult} == 0 ]]; then 
        APPS_PASSWD="${SOURCE_APPS_PASSWD}" 
    else 
        APPS_PASSWD="${TARGET_APPS_PASSWD}" 
    fi 
     
    while [[ -f "${ORACLE_HOME}/.delphix_adpreclone.lck" || $(pgrep -au "${ORACLE_USER}" | grep "^${ORACLE_HOME}" | grep -v grep | grep "adpreclone") ]] ; do 
        if [[ $waittime -gt $timeout ]]; then 
            echo "Another adpreclone process is still running from last 60 mins.Delphix cannot proceed until it is complete. Exiting Now." 
            exit 1 
        fi 
        echo " Another adpreclone process is running. waiting for the process to complete before starting the adpreclone of the database...." 
        (( timeout += 10 )) 
        sleep 10 
    done 
    echo "No other adpreclone process is running on the database, proceeding ...." 
    "${ORACLE_HOME}"/perl/bin/perl "${ORACLE_HOME}/appsutil/scripts/${CONTEXT_NAME}/adpreclone.pl" dbTier <<-EOF 
    ${APPS_PASSWD} 
    EOF 
  7. Pre-Snapshot hook Run Bash Shell Command operation to run any pre-clone steps necessary and specific to your EBS database for a low-privileged user, as shown in the script below. 
    Pre-snapshot hook for a 19c multi-tenant low-privileged user.

    #!/usr/bin/env bash 
    # 
    # Copyright (c) 2022 by Delphix. All rights reserved. 
    # 
    # shellcheck source=/dev/null 
    # As grep has to check all the matches in making decision on L58 
    # shellcheck disable=SC2143 
    # NOTE: Ensure the below environment variables will be set up correctly by the 
    # shell. If not, hardcode or generate the values below. 
    DLPX_DB_EXEC_SCRIPT="<Remote BIN location till dlpx_db_exec script>" 
    DLPX_PRIV_USER=oravis 
    HOSTNAME=$(uname -n | cut -d '.' -f1) 
    CONTEXT_NAME=${DELPHIX_PDB_NAME}_${HOSTNAME} 
    SOURCE_APPS_PASSWD=$DLPX_SOURCE_APPS_PASSWORD_PASSWORD 
    TARGET_APPS_PASSWD=$DLPX_TARGET_APPS_PASSWORD_PASSWORD 
    timeout=3600 
    waittime=0 
     
    # Query active PDB services 
    . "${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env"; 
    check_value=$(sqlplus -s "/ as sysdba" <<EOF 
    SELECT NAME FROM v\$active_services; 
    exit; 
    EOF 
    ) 
     
    checkService() { 
    if ! echo "$1" | grep -q "$2"; then 
    . "${ORACLE_HOME}/${ORACLE_SID}_${HOSTNAME}.env"; 
    sqlplus -s "/ as sysdba" <<EOF 
    alter session set container="${DELPHIX_PDB_NAME}"; 
    BEGIN DBMS_SERVICE.START_SERVICE( service_name => '$2'); 
    end; 
    / 
    EOF 
    fi 
    } 
     
    # Check for ebs_PDB service 
    checkService "$check_value" "ebs_${DELPHIX_PDB_NAME}" 
    # Check for PDB_ebs_patch service 
    checkService "$check_value" "${DELPHIX_PDB_NAME}_ebs_patch" 
     
    . "${ORACLE_HOME}/${CONTEXT_NAME}.env"; 
    testAppsPassword() { 
        local passwordInQuestion=$1 
        ERROR=$("${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; sqlplus apps/\"${passwordInQuestion}\"@${DELPHIX_PDB_NAME} <<< \"exit;\"") 
        grep ORA-01017 <<< "${ERROR}" >/dev/null && return 1 
        return 0 
    } 
    testAppsPassword "${SOURCE_APPS_PASSWD}" 
    testResult=$? 
     
    if [[ ${testResult} == 0 ]]; then 
        APPS_PASSWD=${SOURCE_APPS_PASSWD} 
    else 
        APPS_PASSWD=${TARGET_APPS_PASSWD} 
    fi 
    while [[ -f "${ORACLE_HOME}/.delphix_adpreclone.lck" || $(pgrep -au "${DLPX_PRIV_USER}" | grep "^${ORACLE_HOME}" | grep -v grep | grep "adpreclone") ]] ; do 
        if [[ $waittime -gt $timeout ]]; then 
            echo "Another adpreclone process is still running from the last 60 mins.Delphix cannot proceed until it is complete. Exiting Now." 
            exit 1 
        fi 
        echo " Another adpreclone process is running. waiting for the process to complete before starting the adpreclone of the database...." 
        (( timeout += 10 )) 
        sleep 10 
    done 
    echo "No other adpreclone process is running on the database, proceeding ...." 
    "${DLPX_DB_EXEC_SCRIPT}" -u"${DLPX_PRIV_USER}" ". ${ORACLE_HOME}/${CONTEXT_NAME}.env; ${ORACLE_HOME}/perl/bin/perl ${ORACLE_HOME}/appsutil/scripts/${CONTEXT_NAME}/adpreclone.pl dbTier <<-EOF 
    ${APPS_PASSWD} 
    EOF 
    "