Tasks in the Extensibility Framework

This appendix covers the following topics:

Seeded Tasks in the Extensibility Framework

Oracle E-Business Suite Cloud Manager provides the following seeded tasks that you can add to extended job definitions in the Extensibility Framework.

Table A-1 - Seeded Tasks
Task Name Description
Run AutoConfig on R12.2 Application Tier nodes Stops the application tier services, runs Autoconfig, and brings the application tier services back up.
Run AutoConfig on R12.1 Application Tier nodes Stops all application tier services, runs Autoconfig, and brings the application tier services back up.
Change database archive mode on R12.2 environments Changes the database archive mode on R12.2 environments. All application tier services are restarted.
Change database archive mode on R12.1 environments Changes the database archive mode on R12.1 environments. All application tier services are restarted.
Change database administrator users passwords on R12.2 environments Changes the following database users passwords SYS, SYSTEM, DBSNMP. All application tier services are restarted.

Note: When you submit a job that includes this task, ensure that the password you specify for the SYS user includes at least one special character. However, do not include the @character in a password.

Change database administrator users passwords on R12.1 environments Changes the following database users passwords SYS, SYSTEM, DBSNMP. All application tier services are restarted.

Note: When you submit a job that includes this task, ensure that the password you specify for the SYS user includes at least one special character. However, do not include the @character in a password.

Change APPS password on R12.2 environments Changes the APPS password on R12.2 environments. All application tier services are restarted.
Change APPS password on R12.1 environments Changes the APPS password on R12.1 environments. All application tier services are restarted.
Change Oracle Forms mode from Servlet to Socket on R12.1 environments Changes Oracle Forms mode from Servlet to Socket on R12.1 environments, it runs an implicit AutoConfig. All application tier services are restarted.

Note: When you submit a job that includes this task, ensure that you specify a port number higher than 1024 for the Forms port. This port should be free and should not be used for any other purpose.

Configure Oracle OHS PID and LOCK directory paths on R12.1 environments Configures Oracle OHS PID and LOCK directory paths. All application tier services are restarted. AutoConfig variables s_web_pid_file and s_lock_pid_dir are set, Autoconfig is run and all application tier Services are restarted.
Start Application Tier services for R12.2 environments Starts all application tier services in all nodes of a R12.2 environment
Start Application Tier services for R12.1 environments Starts all application tier services in all nodes of a R12.1 environment
Install RPM from Oracle central yum repository Installs the given RPM from Oracle central yum repository
Create a new WebLogic Monitor user Creates a new WebLogic Monitor user on EBS R12.2 environments
Enable license for products Enables licensing for products determined by the end-user
Run Online Patching fs-clone phase on R12.2 environments Runs Online Patching fs-clone phase on R12.2 environments
Grant EM Monitoring role to a database user Grants the role em_oam_monitor_role to DBSNMP and to a specified user
Change sysadmin user password Changes the sysadmin user password
Install Oracle Support Analyzers Installs Oracle Support Analyzers

Custom Task Scripts in the Extensibility Framework

The Extensibility Framework lets you extend the jobs performed by Oracle E-Business Suite Cloud Manager by adding tasks to meet your own requirements. If you create your own task, you must develop a script that defines the processing performed in the task. Follow these guidelines to develop your custom task script.

  1. Create a wrapper script.

  2. Test the script.

  3. Package the script in a zip file.

For more information, see the following references.

Set Up the Extensibility Framework

Create a Task

Create a Wrapper Script

Each custom task that you want include in Oracle E-Business Suite Cloud Manager jobs must have a wrapper script. The wrapper script is a shell script that contains the top-level definition of the processing performed in the task. When you create the task in the Extensibility Framework UI, you specify this script in the Script to Run field.

The file name for the wrapper script can only contain alphanumeric characters and must end with the file extension .sh.

The wrapper script can parse any input parameters specified for the task, access environment variables, and invoke other types of programs or source other scripts as appropriate for your processing. Except for certain programs available in all Oracle E-Business Suite environments, all the code invoked by the wrapper script must be included together with the wrapper script in a single source code library zip file for the task.

Example Wrapper Script

The following sample code shows an example of a wrapper script for a custom task. In this example, the task is to register a custom schema. This task requires the following input parameters:

Note: For this script to succeed, the custom schema being registered must have the CREATE SESSION privilege.

#!/bin/bash
# +===========================================================================+
# |
# | Copyright (c) 2020 Oracle and/or its affiliates.
# |               All rights reserved.
# |
# +===========================================================================+
# |
# |  FILE : example/extensible_task/RegisterCustomSchema/registerCustomSchema.sh
# |
# +===========================================================================+
# |
# |  DESCRIPTION: This script calls $AD_TOP/patch/115/sql/ADZDREG.sql with required
# |               input parameters.
# |
# |  USAGE      : { echo 'appsPassword=<apps schema password>'; echo 'systemPassword=<system user password>'; }
# |                | sh registerCustomSchema.sh appsUser=<apps user name> customSchemaName=<custom schema>
# |
# +===========================================================================+
#
  
# ===========================================================================+
#        Helper Function definitions 
# ===========================================================================+
  
# Function to exit from a single point
function exitMain(){
    exit 1
}
  
# Function to exit with 0
function exitSuccess(){
    exit 0
}
  
function exitWithUsage(){
    echo "Usage : { echo 'appsPassword=<apps schema password>'; echo 'systemPassword=<system user password>'; } | sh registerCustomSchema.sh appsUser=<apps user name> customSchemaName=<custom schema>"
    exitMain
}
  
  
# ===========================================================================+
#                      Main Script & Argument Parsing
# ===========================================================================+
  
# ===========================================================================+
#    NON Sensitive Parameter Parsing
# ===========================================================================+
# Parse through the argument list each argument in form <argument-name>=<value>
#
function getNonSensitiveParameters(){
    for i in "$@"
    do
        key=`{ echo "${i}"; } | awk -F '=' '{print $1}'`;
        value=`{ echo "${i}"; } | awk -F '=' '{print $2}'`;
         
        # In task-definition - parameter names are "appsUser" and "customSchemaName"
        #
        if [[ "${key}" == "appsUser" ]]; then
            appsUser=$value;
        elif [[ "${key}" == "customSchemaName" ]]; then
            customSchemaName=$value;
        else
           echo "Incorrect arguments password for Non Sensitive Parameters"
           exitWithUsage
        fi
      
    done
}
  
# ===========================================================================+
#    Sensitive Parameter Parsing
# ===========================================================================+
function getSensitiveParameters(){
    while read key_password;
    do
        user_key=`{ echo "$key_password"; } | awk -F '=' '{print $1}'`;
 
        # In task-definition - parameter names are "appsPassword" and "systemPassword"
 
        if [[ "${user_key}" == "appsPassword" ]]; then
            appsPwd=`{ echo "$key_password"; } | awk -F '=' '{print $2}'`
        elif [[ "${user_key}" == "systemPassword" ]]; then
            systemPwd=`{ echo "$key_password"; } | awk -F '=' '{print $2}'`
        else
            echo "Incorrect arguments password for Sensitive Parameters"
            exitWithUsage
        fi
    done
}
  
# ===========================================================================+
#    Getting the CONTEXT_FILE Environment variable
# ===========================================================================+
function getADTOPFromEnv(){
    echo $AD_TOP
}
  
  
# ===========================================================================+
#                       Execution
#       Write Business logic to execute or invoke the scripts..
# ===========================================================================+
getNonSensitiveParameters $@
getSensitiveParameters
adTop=$(getADTOPFromEnv)
 
sqlplus -S apps/$appsPwd  @$adTop/patch/115/sql/ADZDREG.sql $systemPwd $appsUser $customSchemaName
 
if [ "$?" -ne "0" ]; then
    echo "Unable to register custom schema $customSchemaName"
    exitMain
fi
 
# any other business logic can be added here or calling any other scripts or program.
 
# If the execution is successful, can exitSuccess or return 0
exitSuccess

Parse Input Parameters

When you create the task in the Extensibility Framework UI, you can specify input parameters required for the task. Oracle E-Business Suite administrators provide the values for these parameters when they submit a job that includes this task.

You can optionally specify default values for these parameters when you create the task. An administrator can override the default values if necessary when submitting the job.

Additionally, when you create the task, you can specify whether a parameter is considered sensitive or not. The values for sensitive parameters are masked in display in the UI, and are handled separately in processing from parameters that are not sensitive. Sensitive parameter values are passed to the wrapper script through stdin, while values for parameters that are not sensitive are passed as command line arguments.

When the parameter values are passed to the script, the order of the parameters is maintained, and each value is prefixed with the parameter name specified in the task definition, to ensure that each expected parameter has a corresponding value. The wrapper script should read and split the STDIN for sensitive parameters and the command line arguments for parameters that are not sensitive, using the field separator =, to obtain the parameter values.

For examples of how to parse input parameters, review the parameter sections of the example wrapper script.

Access Environment Variables

When you create the task in the Extensibility Framework UI, you can specify whether the task is to be run from all nodes, all database nodes, all application tier nodes, or only the primary application tier node. Before running the wrapper script for a task, the Extensibility Framework sources the environment appropriate for the nodes where the task is being run. For database nodes, the database environment file is sourced, and for application tier nodes, the application environment file is sourced. For Oracle Database 12c or 19c, the pluggable database (PDB) environment file is sourced. Consequently, you can access environment variables such as $CONTEXT_FILE or $APPL_TOP as usual in a shell script.

Because the environment is already sourced, the script can access the variables in the following format: $<variable_name>

For example, you can use the $CONTEXT_FILE variable to access the context file. As another example, if you want to start the admin server by running the adstrtal.sh script, you can use the $ADMIN_SCRIPTS_HOME variable to access the script in that directory:

{ echo $apps_user; echo $apps_pwd; echo $wls_pwd; } | sh $ADMIN_SCRIPTS_HOME/adstrtal.sh -nopromptmsg

You can also use a function to retrieve an environment variable value. The following example shows how to get the AD_TOP environment variable using a function:

function getADTOPFromEnv(){
    echo $AD_TOP
}

The following example shows how to subsequently assign the value of the environment variable:

adTop=$(getADTOPFromEnv)

Invoke Other Programs

From the top-level wrapper script, which is a shell script, you can invoke different types of programs to perform the detailed processing for the task. For example, you can call SQL files, other shell scripts, Perl files, Java programs, and others.

The program file called from the wrapper script must be present in the specified location. Additionally, you must call the programs in non-interactive mode; that is, all the required parameters are passed to the program.

The following examples show sample code for calling a few types of programs. You can use similar code to call other types of programs not specifically shown here, such as Python files.

The following example shows sample code for calling a SQL file:

sqlplus -S apps/$appsPwd  @$adTop/patch/115/sql/ADZDREG.sql $systemPwd $appsUser $customSchemaName

You can invoke another shell script using the sh command. The following example shows sample code for calling a shell script. In this example, the variable $apps_user has already been evaluated to the APPS user, the variable $apps_pwd has already been evaluated to the password for the APPS user, and the variable $wls_pwd has already been evaluated to the Oracle WebLogic Server password.

{ echo $apps_user; echo $apps_pwd; echo $wls_pwd; } | sh $ADMIN_SCRIPTS_HOME/adstrtal.sh -nopromptmsg

All the dependent Perl modules required to run a Perl file are available within the main script that Oracle E-Business Suite Cloud Manager uses to process jobs. The following example shows sample code for calling a Perl file:

{ echo $apps_pwd; } | $FND_TOP/bin/txkrun.pl -script=ChangeFormsMode -contextfile=$CONTEXT_FILE -mode=socket -runautoconfig=yes -port=$socketPort

If you want to call a Java program, that Java program must be in the CLASSPATH in your environments. Java and its dependent libraries are available for the main script to run the command. The following example shows sample code for calling a Java program:

{ echo $apps_pwd; } | java -classpath .:$CLASSPATH  oracle.apps.ad.licmgr.bobj.InstallProduct $fndnam  $APPL_TOP "$products" $apps_jdbc_url $CONTEXT_FILE

Source Other Scripts

From the wrapper script, you can call a function from another shell file. You must first source the other shell file with its relative path. The following example shows sample code for sourcing another shell file:

source ./commonHelper.sh

In this example, the commonHelper.sh script is in the same directory as the script in which it is used.

The commonHelper.sh script is used in seeded tasks provided by Oracle. The common libraries that are used in these tasks are written as functions in the commonHelper.sh script. You can use this script as a reference to write your custom scripts. The following sample code shows the contents of the commonHelper.sh script.

#!/bin/bash
#
# +===========================================================================+
# |
# | Copyright (c) 2020 Oracle and/or its affiliates.
# |               All rights reserved.
# |
# +===========================================================================+
# |
# |  FILE : example/extensible_task/RegisterCustomSchema/commonHelper.sh
# |
# +===========================================================================+
# |
# |  DESCRIPTION: This script is used to provide utility methods to runtime scripts  
# |  USAGE      : This file is sourced by seeded tasks and acts like a library 
# |
# +===========================================================================+

# Global variables 
SYSTEM_USER=system
RETURN_FALSE=1
RETURN_TRUE=0
RETURN_NULL=""
APP_NODE_TYPE="app"
DB_NODE_TYPE="db"

# Function to exit from a single point
function exitMain(){
    exit $RETURN_FALSE
}

# Function to exit with 0
function exitSuccess(){
    exit $RETURN_TRUE
}

# Function to check if the variable passed is empty 
function isNull(){
    retCode=$RETURN_FALSE
    
    if [ -z "$1" ]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
}

# Function to convert a variable to lower case 
function convertToLower(){
    var=$1
    echo $var | tr '[:upper:]' '[:lower:]'
}


# Function to Check if $CONTEXT_FILE exists or not
function checkForContextFile(){
    retCode=$RETURN_FALSE
    
    if [  -f "$CONTEXT_FILE" ] ; then 
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
}

# Check if sqlplus exist 
function checkIfSqlPlusExist()
{   
    retCode=$RETURN_FALSE
    
    sqlplus_path=$(which sqlplus)
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        if [  -f "$sqlplus_path" ]; then
            retCode=$RETURN_TRUE
        fi;
    fi
    
    return $retCode
}

# Get the value from $CONTEXT_FILE
function getCtxValue()
{
    ctxVar=$1
    ctxVal=$(grep $ctxVar $CONTEXT_FILE | sed "s/^.*$ctxVar[^>.]*>[ ]*\([^<]*\)<.*/\1/g; s/ *$//g")
    echo $ctxVal
}

# If the File edition is run returns true else false 
function isRunFileSystem()
{
    retCode=$RETURN_FALSE
    
    file_edition_type=$(getCtxValue s_file_edition_type)
    isNull $file_edition_type
    if [ "$?" -ne "$RETURN_TRUE" ]; then
        if [[ "$file_edition_type" -eq "run"  ]]; then 
            retCode=$RETURN_TRUE
        fi 
    fi

    return $retCode
}


# Get apps version, returns empty if not found 
function getAppsVersion()
{
    version=$RETURN_NULL
    
    apps_version=$(getCtxValue s_apps_version)
    
    isNull $apps_version
    if [ "$?" -ne "$RETURN_TRUE" ]; then
        version=$apps_version
    fi
    
    echo $version
}

# Gets the nodeType
# Returns app/db/empty string    
function getNodeType(){
    node_type=$RETURN_NULL
    
    context_type=$(getCtxValue s_contexttype)
    
    isNull $context_type
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        echo "CONTEXT_FILE may have missing or NULL entry for s_contexttype."
        echo "Please check if the CONTEXT_FILE is corrupted"
    else
        if [[  "${context_type}" == "APPL_TOP Context" ]]; then
            node_type=$APP_NODE_TYPE
        else
            node_type=$DB_NODE_TYPE
        fi
    fi

    echo $node_type

}

# Gets the apps user name from context_file if exists else returns empty string 
function getAppsUser()
{
    apps_user=$(getCtxValue s_apps_user)
    echo $apps_user
}

# Function to return value if key received is same as in keyvalue pair 
# Otherwise returns empty string     
# Example : keyValuePair : apps_password=<apps credentials>  
#           keyReceived  : apps_password   
function getInputValue()
{
    keyValuePair=$1
    keyReceived=$2
    value=$RETURN_NULL

    key=$({ echo "$keyValuePair"; } | awk -F '=' '{print $1}')
    if [[ "$key" == "$keyReceived"  ]]; then
        value=$({ echo "$keyValuePair"; } | awk -F '=' '{print $2}')
    fi

    echo $value
}

# Read apps password from stdin, format of the input : apps_password=value 
function getAppsPassword()
{
    read apps_password
    password=$(getInputValue $apps_password "apps_password")
    echo $password
 
}

# Connect with apps user and apps password 

function validateAppsPassword() {
    apps_user=$1
    apps_pwd=$2
    retCode=$RETURN_FALSE

    isNull $apps_user  
    if [ "$?" -ne "$RETURN_TRUE" ]; then   
        isNull $apps_pwd
        if [ "$?" -ne "$RETURN_TRUE" ]; then           
            checkDBConnection $apps_user $apps_pwd
    
            if [ "$?" -eq "$RETURN_TRUE" ]; then
                retCode=$RETURN_TRUE
            fi
        fi
    fi
    
    return $retCode
}

# Checks user connection 
function checkDBConnection()
{
    user_name=$1
    user_pwd=$2
    retCode=$RETURN_FALSE
    
sqlplus -s /nolog > /dev/null 2>&1 <<EOF
whenever sqlerror exit failure
connect $user_name/$user_pwd
EOF

    if [ "$?" -eq "0" ]; then
        retCode=$RETURN_TRUE
    else
        echo "Database connection could not be established. Either the database is down or the $user_name credentials supplied are wrong."
    fi
    
    return $retCode
}

# To read system password from stdin, Format : system_password=value 
function getSystemPassword()
{
    read system_password
    password=$(getInputValue $system_password "system_password")
    echo $password
}

# Function tries to connect to system user with the password passed 
function validateSystemPassword() 
{   
    system_pwd=$1
    retCode=$RETURN_FALSE
    
    isNull $system_pwd
    if [ "$?" -ne "$RETURN_TRUE" ]; then
        checkDBConnection $SYSTEM_USER $system_pwd
        if [ "$?" -eq "$RETURN_TRUE" ]; then
            retCode=$RETURN_TRUE
        fi
    fi
    
    return $retCode

}

# To read weblogic password from stdin, Format : weblogic_password=value 
# Key is weblogic_password and value is password 
function getWlsPassword()
{
    read weblogic_password
    password=$(getInputValue $weblogic_password "weblogic_password")
    echo $password
}

# Validate WLS Admin credetials 
# ebs-get-serverstatus returns status code of 0 for running mode, 3 is NOT running, 9 Invalid Credentials
function validateWLSAdminCredentials()
{
    wls_pwd=$1
    context_file=$2
    retCode=$RETURN_FALSE
    
    perl_bin=$(getCtxValue s_adperlprg)

    ad_top=$(getCtxValue s_adtop)
    
    if [ -f "$perl_bin" ]; then 
        
        if [ -f "$ad_top/patch/115/bin/adProvisionEBS.pl" ]; then 
           
           { echo $wls_pwd; } | $perl_bin $ad_top/patch/115/bin/adProvisionEBS.pl ebs-get-serverstatus -contextfile=$context_file -servername=AdminServer -promptmsg=hide
           retStatus="$?"
            if [ "$retStatus" -eq "3" ]; then
                echo "Admin Server is NOT running"
            elif [ "$retStatus" -eq "9" ]; then 
                echo "Invalid WebLogic Admin Server user credentials supplied."
            elif [ "$retStatus" -eq "$RETURN_TRUE" ]; then
                echo "Validated Admin Server Credentials successfully"
                retCode=$RETURN_TRUE
            else 
                echo "Invalid return status from $ad_top/patch/115/bin/adProvisionEBS.pl"
            fi
        else 
            echo "Not able to find adProvisionEBS.pl file in the PATH."
            echo "Please check if the environment is sourced."
        fi 
    else
        echo "ERROR : Not able to find PERL executable."
    fi 
    
    return $retCode
}


# Function to check if it is Primary App Node 
function isPrimaryAppNode()
{
    retCode=$RETURN_FALSE
    
    admin_server_status=$(getCtxValue s_adminserverstatus)
    web_admin_status=$(getCtxValue s_web_admin_status)
    if [[ "$admin_server_status" ==  "enabled" && "$web_admin_status" == "enabled" ]]; then
       retCode=$RETURN_TRUE
    fi
    
    return $retCode
}


# Staring the Weblogic Admin Server
function startWLSAdminServer()
{    
    apps_pwd=$1
    wls_pwd=$2
    retCode=$RETURN_FALSE
    
    isPrimaryAppNode
    if [ "$?" -eq "$RETURN_TRUE" ] ; then
        if [ -f "$ADMIN_SCRIPTS_HOME/adadminsrvctl.sh" ]; then 
            { echo $wls_pwd; echo $apps_pwd; }| $ADMIN_SCRIPTS_HOME/adadminsrvctl.sh start -nopromptmsg 

            if [ "$?" -eq "2" ]; then
                echo "Admin Server is already running"
                retCode=$RETURN_TRUE
            elif [ "$?" -eq "$RETURN_TRUE" ]; then 
                echo "Admin Server started successfully"
                retCode=$RETURN_TRUE
            else
                echo "Starting Admin server failed. Please check if valid credentails are passed"      
            fi
        else 
            echo "Not able to find the adadminsrvctl.sh"
            echo "Please check if the environment is sourced"
        fi
    else 
        echo "Not a Primary Node"
    fi
    
    return $retCode

}

# To check if the Domain is editable or not 
function isDomainEditable()
{
    wls_pwd=$1
    
    retCode=$RETURN_FALSE
    
    s_wls_home=$(getCtxValue s_wls_home)
    s_wls_home=$(getCtxValue s_wls_home)
    s_wls_admin_user=$(getCtxValue s_wls_admin_user)
    s_wls_admin_host=$(getCtxValue s_wls_admin_host)
    s_wls_admin_domain=$(getCtxValue s_wls_admin_domain)
    s_wls_adminport=$(getCtxValue s_wls_adminport)
 

    if [[ -z "$s_wls_home" || ! -f "${s_wls_home}/server/bin/setWLSEnv.sh" ]]; then
        echo "Not able to source the WLS environment file."
        echo "Please check if environment is soured.."
    else
        . ${s_wls_home}/server/bin/setWLSEnv.sh
        wls_admin_url="$s_wls_admin_host.$s_wls_admin_domain:$s_wls_adminport"

        if [[ -z "$s_wls_admin_user" || -z "$s_wls_admin_host" || -z "$s_wls_admin_domain" || -z "$s_wls_adminport" ]]; then
            echo "Either one or more of the variables s_wls_admin_user s_wls_admin_host  wls_admin_domain  s_wls_adminport  NULL"
            echo "Please check if environment is sourced "
        else
            if [ -f "$AD_TOP/patch/115/bin/txkValidateDomainInRC.py" ]; then 
            
                { echo $wls_pwd; } | java weblogic.WLST $AD_TOP/patch/115/bin/txkValidateDomainInRC.py --adminuser=$s_wls_admin_user --verify=domainEditModeEnabled --adminurl="$wls_admin_url" | grep -o 'DomainEditable.*1'
                if [ "$?" -eq "$RETURN_TRUE" ]; then
                    echo "Domain is editiable"
                else
                    echo "Domain is in editable mode"
                    retCode=$RETURN_TRUE
                fi
            else
                echo "Not able to find file txkValidateDomainInRC.py"
                echo "Please check if environment is sourced"
            fi
        fi
    fi
    
    return $retCode

}

# Function to shutdown DB on Non RAC Instance 
function shutDownNonRacDB()
{
    retCode=$RETURN_FALSE

sqlplus -s / as sysdba <<END
whenever sqlerror exit failure rollback;
shutdown immediate;
exit;
END
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
}

# Function to startup DB in Mount mode on Non RAC Instance 
function startupNonRacDBMount()
{
    retCode=$RETURN_FALSE

sqlplus -s / as sysdba <<END
whenever sqlerror exit failure rollback;
startup mount;
exit;
END
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
    
}

# Function to startup DB on Non RAC Instance 
function startupNonRacDB()
{
    retCode=$RETURN_FALSE
    
sqlplus -s / as sysdba <<END
whenever sqlerror exit failure rollback;
startup;
exit;
END
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
}

# Function to open Database on Non RAC Instance 
function openNonRacDB()
{
    retCode=$RETURN_FALSE
    
sqlplus -s / as sysdba <<END
whenever sqlerror exit failure rollback;
alter database open;
exit;
END
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
}

# Function to get source cdb environment File
# Intially pdb environment is sourced, if required to change passwords/ archivelog we need to source cdb environment
# Returns the environment if present otherwise NULL is passed to the caller
function getCDBEnvironmentFile()
{
    cdb_env_file=$RETURN_NULL

    instance_name=$(getCtxValue s_instName)
    host_name=$(getCtxValue s_hostname)

    if [[ -z "$instance_name" || -z "$host_name" ]] ; then
        echo "Either or one of the environment variable s_instName, s_hostname is NULL."
    else
        cdb_env_file_path=$ORACLE_HOME/"$instance_name"_"$host_name".env

        if [ ! -f $cdb_env_file_path ]; then
            echo "Not able to find the cdb_env_file. Please check if pdb environment has been sourced."
        else
            cdb_env_file=$cdb_env_file_path
        fi
    fi

    echo $cdb_env_file

}

# Function to check if storage type is ASM or not 
function isStorageTypeASM()
{
    retCode=$RETURN_FALSE 
    host_name=$(getCtxValue s_hostname)
    
    srvctl_path=$(which srvctl)
    if [ "$?" -eq "$RETURN_TRUE" ]; then
        if [  -f "$srvctl_path" ]; then
            ret=$(srvctl status asm -n $host_name | grep -o 'ASM.*running')
            if [ "$?" -eq "$RETURN_TRUE" ]; then
                retCode=$RETURN_TRUE
            fi
        fi;
    fi

    return $retCode
}

# Function to find if the database is pdb enabled or not 
function isPDBEnabled()
{
    retCode=$RETURN_FALSE
    
    is_pdb_enabled=$(getCtxValue s_pluggable_database)
    
    if [[ $is_pdb_enabled == true* || $is_pdb_enabled == TRUE* ]]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode

}

# Function to check if RAC is enabled or not on the instance 
function isRACEnabled()
{
    retCode=$RETURN_FALSE
    
    israc=$(getCtxValue s_dbCluster)
    
    if [[ $israc == true* || $israc == TRUE* ]]; then
        retCode=$RETURN_TRUE
    fi
    
    return $retCode
    
}

# Function to get ORACLE_UNQNAME from environment file 
function getOracleUnqName()
{
    db_unique_name=$RETURN_NULL
    
db_unique_name=$(sqlplus -s / as sysdba <<END
set feedback off heading off
select db_unique_name from sys.v\$database;
exit;
END
)          
    echo $db_unique_name
}

# Function to return password file 
function getPasswordFileLocation()
{
    orapw_file=$RETURN_NULL
    
    isStorageTypeASM
    if [ "$?" -eq "$RETURN_FALSE" ]; then
        # Compute Flows 
        orapw_file=$ORACLE_HOME/dbs/orapw$ORACLE_SID
    else 
        # Platform Flows 
        isPDBEnabled 
        if [ "$?" -eq "$RETURN_TRUE" ]; then
            # Platform Plugable RAC/Non RAC 
            dataloc=$(echo $(getCtxValue s_dbhome1) | awk -F '/' '{print $1}')
            dbname=$(getCtxValue s_cdb_name)
            orapw_file=$dataloc/$ORACLE_UNQNAME/orapw$dbname    
        else 
            # Non Pluggable database. For 11204 Flows 
            isRACEnabled
            if [ "$?" -eq "$RETURN_TRUE" ]; then
                orapw_file="$ORACLE_HOME/dbs/orapw$ORACLE_SID"1
            else
                # Non RAC 
                orapw_file=$ORACLE_HOME/dbs/orapw$ORACLE_SID
            fi
        fi
    fi

    echo $orapw_file
}

# Script executes SQL file as sysdba 
# First argument is FileName and others are parameters 
function executeSQL(){
    retCode=$RETURN_FALSE
    
    if [ ! -f "$1" ]; then 
        echo "Sql file to execute $1 does not exist" 
    else

        sqlplus -s / as sysdba @$1 ${@:2}

        if [ "$?" -eq "$RETURN_TRUE" ]; then
            retCode=$RETURN_TRUE
        fi
    fi
    
    return $retCode
}

Run dos2unix (Windows Only)

If you edit the scripts for your task on Windows, then you may encounter issues with control characters. For example, the following error message indicates a failure caused by a control character:

execution failed with ""/bin/bash^M: bad interpreter: No such file or directory"

To avoid these errors, run the dos2unix command on all the relevant files before you begin packaging the source code for the task. You may need to install dos2unix first if it is not already present on your system. See dos2unix.

For example, the following command runs dos2unix on the example wrapper script:

dos2unix registerCustomSchema.sh

Test the Script

It is recommended that you test your custom script by running directly it on a test instance before you package it for inclusion in a task definition. Before performing the test, source the appropriate environment file and make sure that the prerequisites for the script are present. The following example shows a sample command for testing a script:

{ echo 'appsPassword=<apps schema password>'; echo 'systemPassword=<system user password>'; } | sh registerCustomSchema.sh appsUser=<apps user name> customSchemaName=<custom schema>

Package the Script in a Zip File

When you finish developing the code for your task, you must package the wrapper script in a zip file together with all its supporting files.

  1. Create a directory to hold the code files for the task.

    For example, for the task to register a custom schema, you could create a directory named RegisterCustomSchema.

  2. Move the wrapper script for the task into this directory, along with all the supporting files on which the wrapper script has a dependency.

    For the example task, the wrapper script is registerCustomSchema.sh, and it has a dependency on the commonHelper.sh script for some functions, so you would move both these files into the RegisterCustomSchema directory.

  3. Create a zip file of the entire directory.

    The following example shows the zip command to use for the example task:

    zip -r RegisterCustomSchema.zip RegisterCustomSchema/  
  4. When you create the task in the Extensibility Framework UI, upload this zip file in the Source Code Library field. See Create a Task.