CHAPTER 8

image

Sample EM CLI Scripts

Throughout this book we’ve shown you how to use EM CLI to manage your OEM environment, including using the command line,. I scripting option, which uses JSON and Jython.

This chapter contains some sample scripts for you to adapt to your environment.

  • Section 1: Function Library and Shell Scripts
  • Section 2: EM CLI and Veritas Cluster Services
  • Section 3: Essential OMS Server-Management Scripts
  • Section 4: EM CLI Scripting and Interactive Scripts

Section 1: Function Library and Shell Scripts

Chapter 5 explored various ways you could apply EM CLI with shell scripts. This section expands on those solutions and provides you with sample scripts you can use in your environment.

The samples in this chapter have been edited for clarity, mostly by removing formatting options for echo statements and redirections to log files. Two of the most important things you must provide in your scripts are clear instructions for attended online use and complete log files for unattended execution through Cron or another job scheduler like OEM.

Command-Line Inputs

The use of validated input values provides scalability and ease of use. Before you deploy your scripts, consider adding and testing this important capability.

Nearly all of the scripts in this section require one or more input variables at the command line, often simply the target name. Variables passed at the command line are represented in the body of the script in the order they appear on the command line. The executable file is represented as $0, the first string after that is $1, and so forth. For example, you could have an entry like this:

./oem_target_blackout.sh orcla

This example translates variable $0 as the script name for oem_target_blackout.sh and $1 for the database name. The logic within the scripts should verify that required command-line inputs are not null or that they exit with a clear error statement telling the user or the log file what went wrong. You’ll see several examples of this technique in the sample scripts.

Evidence of Life

Every shell script you develop should be executable at the command line for testing one-off runs, and should also be executable through a scheduler like Cron without any modification. Resist the temptation to use two versions of the same script to enable both modes of operation. This can turn into a maintenance nightmare as the complexity of your environment grows. Instead, test for a live user session by looking at the nature of the session that is calling the script. At run-time, a file system entry for each terminal session will be made in the /dev directory for each live user connection. TTY is an old term for Teletype Session—your terminal session. Cronned executions aren’t called from a terminal, of course, so there is no /dev/tty associated with those executions.

Test for the existence of a TTY session with an if statement and set your runtime variables accordingly. For instance, if your script requires that the database name be passed on the command line, you will respond to missing inputs differently for an attended session than you would for a cronned/scheduled session:

if [ ${1} -eq 0 ]; then
  if tty -s; then
      read -p "Please provide the name of the database: " thisSID
  else
      echo "The database name was not provided on the command line"  >>runtime.log
      exit
   fi
fi

This type of session checking was removed from the example scripts for clarity.

Sample Function Library

This function library is sourced by many of the shell scripts found in the remainder of this section. It can also be sourced for immediate use in a terminal session, or sourced for use in any other shell script.

Sample Script: emcli_functions.lib
#!/bin/sh
#/* vim: set filetype=sh : */
# ==============================================================================
#  File:          emcli_functions.lib
#  Purpose:   Shell script functions for common emcli tasks
#  File permission: This file is sourced and never executed
#  Echo statements: Formatting for echoed statements has been removed for this
#                              scripting sample to keep the logic clear. Be kind to your
#                             users and add white space liberally in your own copy
# ==============================================================================
# The SysmanPassword variable is used in a single place to call your proprietary
# password encryption solution, or in a single location to record the SYSMAN
# password for use in your scripts and within the functions in this library.
# It is strongly recommended that you implement a more secure solution such as encryption/decryption
# through Java or another tool
# ------------------------------------------------------------------------------

SysmanPassword=Sup3r_S3cr3t_PASSWORD

# ==============================================================================
#  General Functions
# ==============================================================================

function CleanUpFiles {
# --------------------------------------------------------------------------------------------------
# CleanUpFiles is called at the beginning of every script to ensure that older
# copies of temporary workfiles are removed to start fresh
# CleanUpFiles is also called by the ExitCleanly function to clean up the
# --------------------------------------------------------------------------------------------------
# files when script execution is complete
# ..............................................................................

[ $WORKFILE ] && rm -f ${WORKFILE}
[ $WORKFILE01 ] && rm -f ${WORKFILE01}
[ $WORKFILE02 ] && rm -f ${WORKFILE02}
}

function ExitCleanly {
# --------------------------------------------------------------------------------------------------
# ExitCleanly is called whenever a script is instructed to exit, whether the
# script ended in success or failure. A clean server is a happy server
# --------------------------------------------------------------------------------------------------

echo "Ending emcli session ..."
emcli logout
CleanUpFiles
echo ""
exit 0
}

function GetAgentNames {
# --------------------------------------------------------------------------------------------------
# As it says in the echo statement, GetAgentNames can be used to list all
# targets of the oracle_emd target type known to OEM
# --------------------------------------------------------------------------------------------------

emcli login -user=sysman -pass="${SysmanPassword}"
echo "Getting the names of all EM agents from OMS ..."
emcli get_targets | grep oracle_emd | sort -u | awk '{ print $4 }'
}

function GetTargetName {
# --------------------------------------------------------------------------------------------------
# This function should be used by any script or function to find
# the exact of a database. If the database isn't known to OEM it returns a
# clear failure message.
# You could easily adapt GetTargetName to find host or agent names
# --------------------------------------------------------------------------------------------------
# Calling script must pass the database name as variable thisSID
# --------------------------------------------------------------------------------------------------

emcli login -user=sysman -pass="${SysmanPassword}"
echo "Getting the exact target name for $thisSID from OMS ..."
if [ `emcli get_targets -targets="oracle_database" | grep -i ${thisSID} | wc -l` -gt 0 ]; then
   thisTARGET=`emcli get_targets -targets="oracle_database" -format="name:csv"
              | grep -i ${thisSID} | cut -d, -f4`
   echo " ${thisTARGET}"
else
   echo "Sorry, ${thisSID} database is not in the OEM repository"
   ExitCleanly
fi
}

# ==============================================================================
#  Blackout Functions
# ==============================================================================

function CreateBlackout {
# --------------------------------------------------------------------------------------------------
# This function was illustrated in Chapter 5 as a method of creating a six-hour
# long blackout on a database target. Adapt the timezone for your environment.
# Consider writing a similar function of entire hosts or an oracle_sys target
# --------------------------------------------------------------------------------------------------
# Calling script must provide a name for the blackout as BO_NAME and the
# database target name as thisSID
# --------------------------------------------------------------------------------------------------

GetTargetName

echo "Creating blackout named '${BO_NAME}' ..."

if [ `emcli get_blackouts | grep ${BO_NAME} | wc -l` -gt 0 ]; then
   echo "Found an existing blackout named ${BO_NAME}"
   echo "That blackout will be stopped and deleted prior to starting the new one"
   emcli stop_blackout -name="${BO_NAME}"
   emcli delete_blackout -name="${BO_NAME}"
fi

emcli create_blackout -name="${BO_NAME}"
   -add_targets=${thisTARGET:oracle_database
   -schedule="duration::360;tzinfo:specified;tzregion:America/Los_Angeles"
   -reason="Scripted blackout for maintenance or refresh"

sleep 5

echo "Getting blackout information for '${BO_NAME}' ..."
emcli get_blackout_details -name="${BO_NAME}"
}

function EndBlackout {
# --------------------------------------------------------------------------------------------------
# This function was illustrated in Chapter 5 as a method of stopping and deleting
# an OEM blackout.
# --------------------------------------------------------------------------------------------------
# Calling script must provide a name for the blackout as BO_NAME
# --------------------------------------------------------------------------------------------------

GetTargetName

echo "Stopping blackout '${BO_NAME}' ..."
emcli stop_blackout -name="${BO_NAME}"

echo "Deleting blackout '${BO_NAME}' ..."
emcli delete_blackout -name="${BO_NAME}"
}

# ==============================================================================
#  Agent Synchronization
# ==============================================================================

function ResyncUnreachableAgents {
# --------------------------------------------------------------------------------------------------
# This function requires no input values to resync all agents found to be in
# an Unreachable state.
#
# Underlying conditions may exist that prevent an individual agent from
# being resync'd, so check agent status after executing this function.
# Only one attempt will be made to resync each agent to prevent an infinite
# loop when problem agents are encountered
#
# This function and SecureAllAgents are written for execution from the command
# line by sourcing this library file and then calling the function by name
#
#   Examples:
#      . emcli_functions.lib
#      ResyncUnreachableAgents
#
#      . emcli_functions.lib
#      SecureAllAgents
# --------------------------------------------------------------------------------------------------

WORKFILE01=/tmp/oem_resyncagents.tmp

CleanUpFiles

emcli login -user=sysman -pass="${SysmanPassword}"

echo "Getting the target name for unreachable agents ..."
if [ `emcli get_targets -targets="oracle_emd" | grep Unreach | awk '{ print $5 }' | wc -l` -gt 0 ]; then
   echo "Creating a list of agents in an Unreachable state"
   emcli get_targets -targets="oracle_emd" | grep Unreachable | awk '{ print $5 }' >${WORKFILE01}
   if [ `cat ${WORKFILE01} | wc -l` -gt 0 ]; then
      for thisAGENT in `cat ${WORKFILE01}`; do
         echo "Attempting to resync ${thisAGENT}"
         echo "This will take quite a while, so please be patient"
         emcli resyncAgent -agent="${thisAGENT}"
      done
   else
      echo "There are currently no unreachable agents"
   fi
else
   echo "There are currently no unreachable agents"
fi

ExitCleanly
}

function SecureAllAgents {
# --------------------------------------------------------------------------------------------------
# As the name suggests, this function will secure all your agents using the
# preferred credentials for their host.
# --------------------------------------------------------------------------------------------------

WORKFILE01=/tmp/oem_secure_agents.tmp

CleanUpFiles

emcli login -user=sysman -pass="${SysmanPassword}"

emcli get_targets | grep oracle_emd | sort -u | awk '{ print $4 }' >${WORKFILE01}

emcli secure_agents -agt_names_file=${WORKFILE01} -use_pref_creds

ExitCleanly
}

# ==============================================================================
# User Account Credentials
# ==============================================================================

function SetDBUserCredential {
# --------------------------------------------------------------------------------------------------
# This function will set the normal database preferred credentials to use the
# SYSMAN password defined at the top of this file.

# --------------------------------------------------------------------------------------------------
# Calling script must provide the database name as thisSID
# --------------------------------------------------------------------------------------------------

emcli set_credential
      -target_type=oracle_database
      -target_name=${thisSID}
      -credential_set=DBCredsNormal
      -columns="username:dbsnmp;password:${SysmanPassword};role:Normal"
}

function SetUserCredential {
# --------------------------------------------------------------------------------------------------
# This function will execute the SetDBUserCredential from the command line
# --------------------------------------------------------------------------------------------------
# You could supplement the failure logic with a read statement to prompt
# for the database name
# --------------------------------------------------------------------------------------------------

if [ ${#1} -gt 0 ]; then
   thisSID=${1}
   SetDBUserCredential
else
   echo "The database name was not set on the command line"
   echo "  syntax:  SetDBUserCredential [database name]
   exit 1
fi
}

Function-Related Shell Scripts

The scripts in this section call or rely on the function described earlier. In each case, the function library is sourced, input values from the command line are evaluated, and key input parameters needed by the functions are set. Notice the simplicity of these scripts. All of the “serious” logic exists in the function library, so when a new script is created you can limit your debugging to just the new code.

Sample Script: emcli_start_blackout.ksh

#!/bin/ksh
# Thus script is written for Korn shell. You must adapt the 'read' statements to use Bash
#
# ==============================================================================
#   File:              emcli_start_blackout.ksh
#   Purpose:       Create and initiate an OEM blackout
#   Parameters:  Database name
# ==============================================================================
# Enter the path to your shell script repository for OEM
FUNCTION_LIB=< Your shared script directory>/emcli_functions.lib

# WORKFILE is one of several file name variables cleaned up by the function library
export WORKFILE=/tmp/create_em_blackout_$PPID.lst

# --------------------------------------------------------------------------------------------------
#  Run-time Procedure
# --------------------------------------------------------------------------------------------------
# Source the function library
. ${FUNCTION_LIB}

# Verify that SID was passed on command line
if [ ${#1} -eq 0 ]; then
   if tty -s; then
      read thisSID? "Please provide the name of the database: "
  else
      echo "The database name was not provided on the command line"
      ExitCleanly
   fi
   read thisSID?"Enter the name of the database to be monitored:  "
else
   thisSID=`print $@ | awk '{print$NF}' | tr '[A-Z]' '[a-z]'`
fi

BO_NAME=scripted_blackout_${thisSID}

CleanUpFiles
CreateBlackout
ExitCleanly

Sample Script: emcli_stop_blackout.ksh

#!/bin/ksh
# ==============================================================================
#   File:             emcli_stop_blackout.ksh
#   Purpose:      Stop and delete a named OEM blackout
#   Parameters:  Database name
# ==============================================================================
# Enter the path to your shell script repository  for OEM
FUNCTION_LIB=< Your shared script directory>/emcli_functions.lib

# WORKFILE is one of several file name variables cleaned up by the function library
export WORKFILE=/tmp/create_em_blackout_$PPID.lst

# --------------------------------------------------------------------------------------------------
#  Run-time Procedure
# --------------------------------------------------------------------------------------------------
# Source the function library
. ${FUNCTION_LIB}

# Verify that SID was passed on command line
if [ ${#1} -eq 0 ]; then
   if tty -s; then
      read thisSID?"Please provide the name of the database: "
  else
      echo "The database name was not provided on the command line"
      ExitCleanly
   fi
   read thisSID?"Enter the name of the database to be monitored again:  "
else
   thisSID=`print $@ | awk '{print$NF}' | tr '[A-Z]' '[a-z]'`
fi

BO_NAME=scripted_blackout_${thisSID}

CleanUpFiles
EndBlackout
ExitCleanly

Section 2: EM CLI and Veritas Cluster Server

Veritas Cluster Servers (VCS)1 are robust fail-over mechanisms deployed as an alternative to RAC One-Node. With VCS, critical resources like database instances are identified and monitored. If a failure is noticed, VCS will unmount drives containing the binaries and database files, remount them on the other node of a cluster, and restart the services.

OEM agents must be installed on a static drive on each host within the cluster. They never fail-over with the VCS resource group because they are strictly associated with a single host. This poses a problem with VCS fail overs. How do you keep track of the targets when the database, its Oracle home, and all of its files move to another host?

Image Tip  Many consider it a best practice on VCS to install the agents on the virtual hostname. Refer to “How to Install 12c Agent on Virtual Hostname / Virtual IP Address?” (Doc ID 1469995.1) for details.

The EM CLI relocate_targets verb transfers responsibility for target tracking to another agent when the targets are relocated by the VCS. This section describes how that process works before showing you the shell script itself.

Program Logic

This script gathers data from the environment and decides which targets are moving and which agents are affected. This script’s scalability and flexibility come from queries of three systems: the VCS cluster, the OEM repository, and the EM agent. Note that syntax is slightly different for relocating responsibility between agents for database and listener targets. We’ll generate a separate set of workfiles for generating the EM CLI argfile that actually performs the work.

Veritas Cluster Server

VCS clusters are organized into groups that drill down to the individual database and listener targets. The hosts in the cluster are at the highest level. VCS heartbeats monitor one or more critical resources on the active node and when necessary relocate all the members2 of a group from the current ONLINE node to the other node that is currently OFFLINE. We’ll use this knowledge to determine the host and agent names we need to manage.

Since EM agents can only monitor targets that run from the same host (or Oracle cluster), we need to carefully determine which targets are related to the VCS group being failed-over. Those database and listener targets are the only targets eligible for relocation through EM CLI. We’ll use a second set of VCS query results to decide which EM targets need to be relocated.

For example, let’s say you have two Oracle installations, each with their own Oracle base filesystem. Each base, or home, contains all the files required to support its own targets, of course, and many databases and listeners may use those homes. They are all members of one fail-over group. Let’s say the groups are named QUAL and TEST.

  • The QUAL group has one database named alexis_q with a listener named LSNRQ.
  • TEST group has three databases, alexis_t1, alexis_t2, and alexis_t3, and a shared listener named LSNRT.
  • Alexis_q database is identified as the critical resource for the QUAL cluster group.
  • All three databases in the TEST cluster group are identified as “critical resources” in the TEST cluster group.

If VCS does not receive a response back from its heartbeat against the alexis_q, all the resources in the QUAL cluster group will fail-over to the other node.

If any of three databases in the TEST node becomes unresponsive, everything on that node, including the healthy databases, will be restarted by VCS on the other node.

A VCS relocation often takes only a moment or two while the healthy members of the resource group (other databases sharing the binaries and any related listeners) are brought down, filesystems are unmounted and then re-mounted, and finally all the resources are brought up. Manual intervention is not required.

Oracle Enterprise Manager

Databases and listeners on either host may have been ignored, dropped, or simply never discovered in Enterprise Manager, so there’s nothing to change in OEM. We’ll check both the EM repository and the local agent to decide which targets need to be relocated.3

In this example, only databases alexis_q and alexis_t1 are configured for monitoring in OEM. The EM agent knows about all of them, of course, but OEM monitoring and metrics collection only apply to the first two and their respective listeners. As far as OEM is concerned, we can ignore the other two databases completely. After the relocation is complete, the agent on the new node will discover alexis_t2 and alexis_t3 as part of its own host discovery. The agent on the other node also performs regular searches for new targets, so it will essentially forget about the unmonitored databases. The EM CLI command will transfer its knowledge about the history, metric collections, and preferred credentials for alexis_q and alexis_t1. That knowledge transfer is the purpose of this exercise, after all.

Implementation  

The emcli_relocate_target_vcs.ksh script is executed without command-line input parameters by VCS after all the other fail-over tasks are complete, including restarting the databases and listeners:

Sample Script: emcli_relocate_target_vcs.ksh

#!/bin/sh
# ==============================================================================
#  File:            emcli_relocate_target_vcs.sh
#  Purpose:     Relocate OEM agent for monitored VCS targets
#  Parameters: VCS group name required
#  Note:           Must be run as part of  VCS startup to run after fail-over
#                      to the secondary host
# ==============================================================================
# Environment tests
# --------------------------------------------------------------------------------------------------
if [ ${#1} -eq 0 ]; then
   echo "You must pass the VCS cluster name on the command line "
   exit 1
fi

export VCSBIN=< Set to the bin directory for your VRTSvcs executables >

if [ ! -d ${VCSBIN} ]; then
   echo  "Could not locate the Veritas executables in ${VCSBIN}"
   export VCSBIN=""
   exit 1
fi

# --------------------------------------------------------------------------------------------------
# Variables section
# --------------------------------------------------------------------------------------------------
SCRIPTNAME=`basename ${0}`
LOCAL_HOST=`hostname | cut -d"." -f1`

# --------------------------------------------------------------------------------------------------
# Set the ORACLE_HOME to the agent's base directory
# EM agent installs with its own jdk, so reference it in this script
# --------------------------------------------------------------------------------------------------
export ORACLE_HOME=/u01/oracle/product/agent12c
export EMCTL_HOME=${ORACLE_HOME}/agent_inst/bin
export JAVA_HOME=${ORACLE_HOME}/core/12.1.0.3.0/jdk/bin
# --------------------------------------------------------------------------------------------------
# The settings shown assume EM CLI binaries reside in the agent O/H
# --------------------------------------------------------------------------------------------------

export EMCLI_HOME=${ORACLE_HOME}/emcli

# Set paths to match the values set above

export PATH=${VCS_BIN}:${PATH}
export PATH=${ORACLE_HOME}:${ORACLE_HOME}/bin:${PATH}
export PATH=${EMCTL_HOME}:${PATH}
export PATH=${JAVA_HOME}:${PATH}
export PATH=${EMCLI_HOME}:${PATH}

export PATH=${PATH}:.
export LD_LIBRARY_PATH=${ORACLE_HOME}/lib:/lib:/lib64:/usr/lib:/usr/lib64

# Set fully-qualified paths to the executables here

export EMCLI=${EMCLI_HOME}/emcli
export EMCTL=${EMCTL_HOME}/emctl
export JAVA=${JAVA_HOME}/java

export IBM_JAVA_OPTIONS=-Djava.net.preferIPv4Stack=true

# Required setting for an AIX environment

export AIXTHREAD_SCOPE=S

# --------------------------------------------------------------------------------------------------
# File name variables - keep these in the same order as CleanUpFiles function
# --------------------------------------------------------------------------------------------------
# Lists will be collected from each of source as listed and distilled into the
# final EM CLI script
#
# emcli relocate_targets verb syntax is slightly different for databases and
# listeners so we'll collect them in separate lists of targets for processing
# --------------------------------------------------------------------------------------------------

VCS_DATABASES=/tmp/RelocateTargetDatabases_VCS.lst
VCS_LISTENERS=/tmp/RelocateTargetListeners_VCS.lst

EMCLI_DATABASES=/tmp/RelocateTargetDatabases_EMCLI.lst
EMCLI_LISTENERS=/tmp/RelocateTargetListeners_EMCLI.lst

EMCTL_DATABASES=/tmp/RelocateTargetDatabases_EMCTL.lst
EMCTL_LISTENERS=/tmp/RelocateTargetListeners_EMCTL.lst

OEM_DATABASES=/tmp/RelocateTargetDatabases_OEM.lst
OEM_LISTENERS=/tmp/RelocateTargetListeners_OEM.lst

MOVING_DATABASES=/tmp/RelocateTargetDatabases_Moving.lst
MOVING_LISTENERS=/tmp/RelocateTargetListeners_Moving.lst

EMCLI_SCRIPT=/tmp/RelocateTarget_emcli_script.lst

#===============================================================================
# Functions
#===============================================================================

function CleanUpFiles {
# --------------------------------------------------------------------------------------------------
[ $VCS_DATABASES ] && rm -f ${VCS_DATABASES}
[ $VCS_LISTENERS ] && rm -f ${VCS_LISTENERS}
[ $EMCLI_DATABASES ] && rm -f ${EMCLI_DATABASES}
[ $EMCLI_LISTENERS ] && rm -f ${EMCLI_LISTENERS}
[ $EMCTL_DATABASES ] && rm -f ${EMCTL_DATABASES}
[ $EMCTL_LISTENERS ] && rm -f ${EMCTL_LISTENERS}
[ $OEM_DATABASES ] && rm -f ${OEM_DATABASES}
[ $OEM_LISTENERS ] && rm -f ${OEM_LISTENERS}
[ $MOVING_DATABASES ] && rm -f ${MOVING_DATABASES}
[ $MOVING_LISTENERS ] && rm -f ${MOVING_LISTENERS}
[ $EMCLI_SCRIPT ] && rm -f ${EMCLI_SCRIPT}
}

function ExitCleanly {
# --------------------------------------------------------------------------------------------------
CleanUpFiles
exit 0
}

function ExitDirty {
# --------------------------------------------------------------------------------------------------
CleanUpFiles
exit 1
}

function ListNicely {
# --------------------------------------------------------------------------------------------------
for thisLINE in `cat ${thisFILE}`; do
   echo "  ${thisLINE}"
done
}

# --------------------------------------------------------------------------------------------------
# Runtime procedure
# --------------------------------------------------------------------------------------------------
# Time stamp for the VCS log file
# --------------------------------------------------------------------------------------------------
echo " ---------------------------------------------------------------------"
date
echo "--------------------------------------------------------------------- "

CleanUpFiles

 # -------------------------------------------------------------------------------------------------
# Gather VCS values for the members of the cluster
# --------------------------------------------------------------------------------------------------
# Test whether VCS recognizes the cluster name you passed at the command line
# by checking for the existence of node in OFFLINE mode. From that knowledge
# we can get the name of the HAGROUP and then associate the offline and online
# nodes with the appropriate variable based on their status after the
# VCS fail-over

if [ `sudo ${VCSBIN}/hastatus -summary | grep OFFLINE | grep ${1} | wc -l` -eq 0 ]; then
   echo " The VCS cluster ${1} does not exist on ${LOCAL_HOST} "
   ExitDirty
else
   export HAGROUP=`sudo ${VCSBIN}/hastatus -summary | grep OFFLINE | grep ${1} | awk '{ print $2 }'`
   export OFFLINE_NODE=`sudo ${VCSBIN}/hastatus -summary | grep OFFLINE | grep ${HAGROUP} | awk '
{ print $3 }'`

   if [ `sudo ${VCSBIN}/hastatus -summary | grep ONLINE | grep ${HAGROUP} | wc -l` -gt 0 ]; then
      export ONLINE_NODE=`sudo ${VCSBIN}/hastatus -summary | grep ONLINE | grep ${HAGROUP} | awk '{ print $3 }'`
   else
      export ONLINE_NODE=`sudo ${VCSBIN}/hastatus -summary | grep PARTIAL | grep ${HAGROUP} | awk '{ print $3 }'`
   fi
fi

# --------------------------------------------------------------------------------------------------
# Echo those values for the log file
# --------------------------------------------------------------------------------------------------
echo " Veritas Cluster names:"
echo "  VCS group                            ${HAGROUP}"
echo "  Active node after relocation  ${ONLINE_NODE}"
echo "  Offline node                          ${OFFLINE_NODE}"
echo "  Local hostname                     ${LOCAL_HOST}"

# --------------------------------------------------------------------------------------------------
# Select the database and listener names associated with the HAGROUP
# This list may not match the list of targets known to OEM on these hosts, so we'll compare
# them later in the script
# --------------------------------------------------------------------------------------------------
sudo ${VCSBIN}/hares -display -type Oracle  | grep ${HAGROUP} | awk '{ print $1 }' >${VCS_DATABASES}
sudo ${VCSBIN}/hares -display -type Netlsnr | grep ${HAGROUP} | awk '{ print $1 }' >${VCS_LISTENERS}

if [ `cat ${VCS_DATABASES} | wc -l` -gt 0 ]; then
   echo " VCS shows these databases in ${HAGROUP} group"
   thisFILE=${VCS_DATABASES}
   ListNicely
else
   echo " VCS has no databases associated with ${HAGROUP} group"
   ExitDirty
Fi

if [ `cat ${VCS_LISTENERS} | wc -l` -gt 0 ]; then
        echo " VCS shows these listeners in ${HAGROUP} group"
        thisFILE=${VCS_LISTENERS}
        ListNicely
Else
        echo " VCS has no listeners associated with ${HAGROUP} group"
fi

if [ ${OFFLINE_NODE} == ${LOCAL_HOST} ]; then
   echo " The ${HAGROUP} group is located on the other side of the cluster"
   echo "This script must be run on the active node ${ONLINE_NODE} "
   ExitDirty
Fi
# --------------------------------------------------------------------------------------------------
# Get OEM agent names, including ports, for both nodes
# Agents are always installed on a static file system and never fail over
# --------------------------------------------------------------------------------------------------
NEW_EMD=`$EMCLI get_targets | grep ${ONLINE_NODE}  | grep oracle_emd |  awk '{print $NF }'`
OLD_EMD=`$EMCLI get_targets | grep ${OFFLINE_NODE} | grep oracle_emd |  awk '{print $NF }'`

# --------------------------------------------------------------------------------------------------
# This string will be used several times during emcli script construction
# --------------------------------------------------------------------------------------------------
EMCLI_AGENT_STRING=`echo "-src_agent="${OLD_EMD}" -dest_agent="${NEW_EMD}""`

echo " OEM names for the host targets related to this change:"
echo "  Host after relocation         ${NEW_EMD}"
echo "  Local host name               ${OLD_EMD}"

# --------------------------------------------------------------------------------------------------
# Create and distill lists of OEM targets
# Not all targets are managed by OEM, so we need to get a list from the repository
# that we'll compare with the list from VCS
# --------------------------------------------------------------------------------------------------

$EMCLI get_targets | grep oracle_database | awk '{print $NF}' | sort -fu >${EMCLI_DATABASES}

echo " Database targets managed through OEM:"
thisFILE=${EMCLI_DATABASES}
ListNicely

$EMCLI get_targets | grep oracle_listener | awk '{print $NF}' | sort -fu >${EMCLI_LISTENERS}
echo " Listener targets managed through OEM:"
thisFILE=${EMCLI_LISTENERS}
ListNicely

# --------------------------------------------------------------------------------------------------
# Now we'll do the same thing for targets known to the local EM agent. This list
# may include targets ignored or unpromoted in the repository, so we'll treat the
# agent list as a better choice. If the local agent has no targets we'll use
# the full list from the repository
# --------------------------------------------------------------------------------------------------

$EMCTL config agent listtargets | grep oracle_database | cut -d"[" -f2 | cut -d, -f1 | sort -fu  
>${EMCTL_DATABASES}

echo " Local database targets currently associated with ${NEW_EMD}:"
thisFILE=${EMCTL_DATABASES}
ListNicely

$EMCTL config agent listtargets | grep oracle_listener | cut -d"[" -f2 | cut -d, -f1 | sort -fu  
>${EMCTL_LISTENERS}

echo " Local listener targets currently associated with ${NEW_EMD}:"
thisFILE=${EMCTL_LISTENERS}
ListNicely

# --------------------------------------------------------------------------------------------------
# The longer list from the repository was created in case the local agent did not
# contain any targets. We'll replace the OMR list with the targets known to the
# local agent if any exist
# --------------------------------------------------------------------------------------------------

if [ `cat ${EMCTL_DATABASES} | wc -l` -gt 0 ]; then
   cat /dev/null                            >${OEM_DATABASES}
   for thisTARGET in `cat ${EMCLI_DATABASES}`; do
      if [ `cat ${EMCTL_DATABASES} | grep -i ${thisTARGET} | wc -l` -eq 0 ]; then
         echo "${thisTARGET}"              >>${OEM_DATABASES}
      fi
   done
else
   mv -f ${EMCLI_DATABASES} ${OEM_DATABASES}
fi

# --------------------------------------------------------------------------------------------------
# Same process happens for the listeners
# --------------------------------------------------------------------------------------------------

if [ `cat ${EMCTL_LISTENERS} | wc -l` -gt 0 ]; then
   cat /dev/null                            >${OEM_LISTENERS}
   for thisTARGET in `cat ${EMCLI_LISTENERS}`; do
      if [ `cat ${EMCTL_LISTENERS} | grep -i ${thisTARGET} | wc -l` -eq 0 ]; then
         echo "${thisTARGET}"              >>${OEM_LISTENERS}
      fi
   done
else
   mv -f ${EMCLI_LISTENERS} ${OEM_LISTENERS}
fi

# --------------------------------------------------------------------------------------------------
# Compare the OEM target list with the Veritas members and build emcli scripts
# --------------------------------------------------------------------------------------------------

if [ `cat ${VCS_DATABASES} | wc -l` -gt 0 ]; then
   cat /dev/null                            >${MOVING_DATABASES}
   for thisITEM in `cat ${VCS_DATABASES}`; do
      cat ${OEM_DATABASES} | grep -i ${thisITEM} >>${MOVING_DATABASES}
   done
fi

cat /dev/null                            >${EMCLI_SCRIPT}

if [ `cat ${MOVING_DATABASES} | wc -l` -gt 0 ]; then
   echo " These database targets will be relocated"
   thisFILE=${MOVING_DATABASES}
   ListNicely
   for thisITEM in `cat ${MOVING_DATABASES}`; do
      EMCLI_TARGET_STRING=`echo "-target_name="${thisITEM}" -target_type="oracle_database""`
      echo "set_standby_agent ${EMCLI_AGENT_STRING} ${EMCLI_TARGET_STRING}"  >>${EMCLI_SCRIPT}
      echo "relocate_targets  ${EMCLI_AGENT_STRING} ${EMCLI_TARGET_STRING} -copy_from_src
-force=yes" >>${EMCLI_SCRIPT}

   done
else
   echo " No database targets need to be migrated to ${NEW_EMD}"
fi

if [ `cat ${VCS_LISTENERS} | wc -l` -gt 0 ]; then
   cat /dev/null                            >${MOVING_LISTENERS}
   for thisITEM in `cat ${VCS_LISTENERS} | sed 's/lsnr//'`; do
      cat ${OEM_LISTENERS} | grep -i ${thisITEM} >>${MOVING_LISTENERS}
   done
else
   echo " VCS has no listeners associated with ${HAGROUP} group"
fi

if [ `cat ${MOVING_LISTENERS} | wc -l` -gt 0 ]; then
   echo " These listener targets will be relocated to ${NEW_EMD}"
   thisFILE=${MOVING_LISTENERS}
   ListNicely
   for thisITEM in `cat ${MOVING_LISTENERS}`; do
      EMCLI_TARGET_STRING=`echo "-target_name="${thisITEM}" -target_type="oracle_listener""`
      echo "set_standby_agent ${EMCLI_AGENT_STRING} ${EMCLI_TARGET_STRING}" >>${EMCLI_SCRIPT}
      echo "relocate_targets  ${EMCLI_AGENT_STRING} ${EMCLI_TARGET_STRING} -copy_from_src"
>>${EMCLI_SCRIPT}

   done
else
   echo " No listener targets need to be migrated to ${NEW_EMD}"
fi

sleep 10

# --------------------------------------------------------------------------------------------------
#  Show the emcli to the log file and then execute it with emcli argfile
# --------------------------------------------------------------------------------------------------

if [ `cat ${EMCLI_SCRIPT} | wc -l` -gt 0 ]; then
   echo " EMCLI script"
   cat ${EMCLI_SCRIPT}
   echo " EMCLI execution results"
   $EMCLI argfile ${EMCLI_SCRIPT}
fi

echo " These targets are now tracked by the local OEM agent: "
$EMCTL config agent listtargets | grep -v "Cloud" | grep -v "reserved." | sort -fu
echo " "

ExitCleanly

Section 3: Essential Server-Management Scripts

The shell scripts in this section contain various uses of EM CLI, including backing up all configuration files on your OMS server and then controlling the amount of space consumed by OMS log files.

Oracle has been very good about providing these services for files they deem critical. These scripts take care of all the rest.

Configuration Backup Script

OEM backs up key OMS configuration files to the repository database. This script performs a file-level backup for those files (and several others).  One should use the same shared filesystem used by the Software Library as the site of those backups.

This script only creates new backups when it determines that the source file has different content than its backup copy. If a difference exists, the old backup is renamed with a .old suffix. This provides you with another troubleshooting tool that can be particularly helpful after OMS patching. You can use file creation dates to determine which configuration files changed and then run a quick diff command to find out how they changed:

Sample Script: backup_oms_configs.ksh
#!/bin/ksh

#===============================================================================
#  Script name  : backup_oms_configs.ksh
#  Calling args : None
#  Purpose      :   Backup key OMS configuration files
#===============================================================================
# Independent variables
#===============================================================================
export OMS_HOME=<Set your OMS home directory here>
export BACKUP_DIR=<Set backup destination directory here>

#===============================================================================
# Functions
#===============================================================================
function DashedBreak {
echo " -------------------------------------------------------------------------------- "
}

function PrepareBackupDir {

SOURCE_DIR=${OMS_HOME}/${DIRNAME}
TARGET_DIR=${BACKUP_DIR}/${DIRNAME}
STAGE_DIR=${TARGET_DIR}/staging
if [ -d ${TARGET_DIR} ]; then
   echo " Found directory ${TARGET_DIR} "
else
   echo " Creating directory ${TARGET_DIR} "
   mkdir -p ${TARGET_DIR}
fi

chmod 770 ${TARGET_DIR}

if [ ! -d ${STAGE_DIR} ]; then
   mkdir ${STAGE_DIR}
fi

chmod 770 ${STAGE_DIR}
}

function BackupConfigFile {

sourceFILE=${SOURCE_DIR}/${FILENAME}
stageFILE=${TARGET_DIR}/staging/${FILENAME}
targetFILE=${TARGET_DIR}/${FILENAME}
oldFILE=${targetFILE}.old
oldZIP=${oldFILE}.zip

DashedBreak

if [ -f ${sourceFILE} ]; then
   if [ -f ${targetFILE} ]; then
      echo " Backing up ${sourceFILE} "
      cp -f ${sourceFILE} ${stageFILE}
      if [ `diff ${stageFILE} ${targetFILE} | wc -l` -gt 1 ]; then
         echo " Existing backup file will be renamed and gzipped "
            if [ -f ${targetFILE} ]; then
               ## Get rid of older copies of both files
               [ $oldZIP ] && rm -f ${oldZIP}
               [ $oldFILE ] && rm -f ${oldFILE}
               ## Rename and gzip the latest backup copy
               echo " Renaming the existing backup file "
               mv ${targetFILE} ${oldFILE}
               echo " Gzipping that copy "
               gzip -f ${oldFILE} --fast
               chmod 600 ${oldZIP}
            fi
         echo " Backing up ${sourceFILE} "
         mv ${stageFILE} ${targetFILE}
         chmod 640 ${targetFILE}
         echo " New backup file moved into place "
      else
         echo " The current copy of ${FILENAME} is identical to the backup copy "
         rm -f ${stageFILE}
      fi
   else
      echo " Making a copy of ${sourceFILE} "
      cp ${sourceFILE} ${targetFILE}
   fi
   echo " ${sourceFILE} does not exist on this server "
fi

chmod 640 ${targetFILE}

echo " Finished "
}

# =========================================================================
#  Run-time Procedure
# =========================================================================

echo " Backup directories and contents before processing "
ls -lARp ${BACKUP_DIR} | grep -v "^total"

DashedBreak

# --------------------------------------------------------------------------------------------------
# Script sets the directory name and then lists each file
# subject to backup. The functions turn the values set as DIRNAME
# and FILENAME into source and target names for processing
# --------------------------------------------------------------------------------------------------

FILENAME=access.conf
   BackupConfigFile

FILENAME=mod_osso.conf
   BackupConfigFile

FILENAME=oracle_apache.conf
   BackupConfigFile

FILENAME=httpd.conf
   BackupConfigFile

FILENAME=ssl.conf
   BackupConfigFile

FILENAME=mod_oc4j.conf
   BackupConfigFile

FILENAME=dms.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=Apache/jsp/conf
   PrepareBackupDir

FILENAME=ojsp.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=Apache/modplsql/conf
   PrepareBackupDir

FILENAME=cache.conf
   BackupConfigFile

FILENAME=plsql.conf
   BackupConfigFile

FILENAME=dads.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=Apache/oradav/conf
   PrepareBackupDir

FILENAME=oradav.conf
   BackupConfigFile

FILENAME=moddav.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=datadirect/lib
   PrepareBackupDir

FILENAME=krb5.conf
   BackupConfigFile

FILENAME=JDBCDriverLogin.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=dsa
   PrepareBackupDir

FILENAME=dsa.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=dcm/config
   PrepareBackupDir

FILENAME=dcm.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=dcm/config/plugins/apache
   PrepareBackupDir

FILENAME=httpd.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=diagnostics/config
   PrepareBackupDir

FILENAME=logloader.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=iaspt/conf
   PrepareBackupDir

FILENAME=iaspt.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/home/application-deployments/IsWebCacheWorking
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/home/application-deployments/portletapp
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

FILENAME=orion-application.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/OC4J_EM/config
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

FILENAME=jazn.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/OC4J_EMPROV/application-deployments/em
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/OC4J_EMPROV/application-deployments/EMAgentPush
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

FILENAME=orion-application.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/OC4J_EMPROV/config
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

FILENAME=jazn.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/OCMRepeater/application-deployments/OCMRepeater
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=j2ee/OCMRepeater/config
   PrepareBackupDir

FILENAME=jazn-data.xml
   BackupConfigFile

FILENAME=jazn.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=ldap/das
   PrepareBackupDir

FILENAME=oiddas.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=opmn/conf
   PrepareBackupDir

FILENAME=ons.conf
   BackupConfigFile

FILENAME=opmn.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=sysman/config
   PrepareBackupDir

FILENAME=httpd_em.conf
   BackupConfigFile

FILENAME=agentpush.conf
   BackupConfigFile

FILENAME=agent_download.conf
   BackupConfigFile

FILENAME=emoms.properties
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=sysman/emd
   PrepareBackupDir

FILENAME=lastupld.xml
   BackupConfigFile

FILENAME=targets.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=sysman/j2ee/applications/Oc4jDcmServlet/META-INF
   PrepareBackupDir

FILENAME=application.xml
   BackupConfigFile

FILENAME=orion-application.xml
   BackupConfigFile

FILENAME=jazn-data.xml
   BackupConfigFile

FILENAME=principals.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=sysman/j2ee/applications/Oc4jDcmServlet/Oc4jDcmServlet/WEB-INF
   PrepareBackupDir

FILENAME=orion-web.xml
   BackupConfigFile

FILENAME=web.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=sysman/j2ee/application-deployments/Oc4jDcmServlet
   PrepareBackupDir

FILENAME=orion-application.xml
   BackupConfigFile

FILENAME=orion-web.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=sysman/webapps/emd/online_help
   PrepareBackupDir

FILENAME=ohwconfig.xml
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=uix
   PrepareBackupDir

FILENAME=uix.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=wcs/config
   PrepareBackupDir

FILENAME=wcs_httpd.conf
   BackupConfigFile

# --------------------------------------------------------------------------------------------------

DIRNAME=webcache
   PrepareBackupDir

FILENAME=internal.xml
   BackupConfigFile

DashedBreak

echo " Backup directories and contents after processing "
ls -lARp ${BACKUP_DIR} | grep -v "^total"

Transitory File Cleanup Script

Oracle Management Server generates logs for each of its components, from the WebLogic server down to the EM agent on the host. Preinstalled rotations and file cleanup are very helpful where they exist, but some of the files aren’t managed that way. It’s up to you to keep your server tidy.

This script works its way through the log directories on an OMS server. Each file is evaluated for how long it has been idle. Older files are then removed:

#!/bin/ksh
#===============================================================================
#  Script name  : log_blaster_oms.ksh
#  Calling args : None
#  Purpose      : Clean up logs files for OMS
#                       References come from MOS Note 1445743.1
#===============================================================================
#  Independent variables
#=================================================================
# Set these variables to your local directory settings
# The EM_INSTANCE_HOME is typically MIDDLEWARE_HOME/gc_inst
EM_INSTANCE_HOME=

WORKFILE=/tmp/logblaster_oms_workfile1.lst

#=================================================================
#  Functions
# =================================================================

function CleanUpFiles {
# --------------------------------------------------------------------------------------------------

[ $WORKFILE ] && rm -f ${WORKFILE}
}

function TrimThisFile {
# --------------------------------------------------------------------------------------------------
if [ -d ${thisDIR} ]; then
   if [ `find ${thisDIR} -name ${thisFILE} | wc -l` -gt 0 ]; then
      NEW_FILE=${thisDIR}/${thisFILE}
      OLD_FILE=${thisDIR}/${thisFILE}_old
      LAST_DATE=`tail -1 ${NEW_FILE} | awk '{ print $1,$2,$3 }'`
      echo " Trimming ${NEW_FILE}"
      echo "Entries older than ${LAST_DATE} will be removed "
      mv -f ${NEW_FILE} ${OLD_FILE}
      cat ${OLD_FILE} | grep "${LAST_DATE}" >${NEW_FILE}
         if [ `cat ${NEW_FILE} | wc -l` -gt 0 ]; then
            rm -f ${OLD_FILE}
         else
            mv -f ${OLD_FILE} ${NEW_FILE}
      fi
   fi
   echo " "
else
   echo " Directory ${thisDIR} not found "
fi
}

function SweepThese {
# --------------------------------------------------------------------------------------------------
if [ -d ${thisDIR} ]; then
   find ${thisDIR} -name ${thisFILE} -mtime +${thisAGE} >${WORKFILE}
   if [ `cat ${WORKFILE} | wc -l` -gt 0 ]; then
      echo " Cleaning up ${thisDIR} directory"
      for thisTRASH in `cat ${WORKFILE}`; do
         echo" Removing ${thisTRASH}"
         rm -f ${thisTRASH}
      done
   else
      echo " No files over ${thisAGE} days old matching"
      echo "${thisDIR}/${thisFILE}"
   fi
   echo " "
else
   echo " Directory ${thisDIR} not found "
fi
}

# --------------------------------------------------------------------------------------------------
#  Run-time procedure
# --------------------------------------------------------------------------------------------------

CleanUpFiles

# --------------------------------------------------------------------------------------------------
# The webtier directory name is pulled from the environment
# Typically the value discovered  OMS1, but it may be different
# --------------------------------------------------------------------------------------------------

WEBTIERn=`ls ${EM_INSTANCE_HOME} | grep WebTier`

OHSn=`ls ${EM_INSTANCE_HOME}/${WEBTIERn}/diagnostics/logs/OHS | grep ohs`

# --------------------------------------------------------------------------------------------------
# Retention for this directory is set for seven days through thisAGE variable
# --------------------------------------------------------------------------------------------------

thisDIR=${EM_INSTANCE_HOME}/${WEBTIERn}/diagnostics/logs/OHS/${OHSn}
   thisAGE=7

thisFILE="em_upload_http_access_log.*"
   SweepThese

thisFILE="em_upload_https_access_log.*"
   SweepThese

thisFILE="access_log.*"
   SweepThese

thisFILE="ohs*.log"
   SweepThese

thisFILE="console~OHS*.log*"
   SweepThese

thisFILE="mod_wl_ohs.log"
   TrimThisFile

# --------------------------------------------------------------------------------------------------

DOMAIN_SERVERS_DIR=${EM_INSTANCE_HOME}/user_projects/domains/GCDomain/servers

thisDIR=${DOMAIN_SERVERS_DIR}/EMGC_ADMINSERVER/logs
   thisAGE=7

thisFILE="GCDomain.log*"
   SweepThese

thisFILE="EMGC_ADMINSERVER.out*"
   SweepThese

thisFILE="EMGC_ADMINSERVER.log*"
   SweepThese

thisFILE="EMGC_ADMINSERVER-diagnostic-*.log"
   SweepThese

thisFILE="access.log*"
   SweepThese

# --------------------------------------------------------------------------------------------------

EMGC_OMSn=`ls ${DOMAIN_SERVERS_DIR} | grep OMS`

thisDIR=${DOMAIN_SERVERS_DIR}/${EMGC_OMSn}/logs
   thisAGE=7

thisFILE="EMGC_OMS*.out*"
   SweepThese

for eachDIR in `ls -1 /oraoms/exportconfig`; do
   thisDIR=/oraoms/exportconfig/${eachDIR}
   thisFILE="opf_ADMIN_*.bka"
   SweepThese
Done

CleanUpFiles
exit 0

Section 4: EM CLI Scripting and Interactive Scripts

Release 3 of Enterprise Manager includes both the standard command-line-only version of EM CLI as well as a version with a robust scripting option (sometimes referred to as the advanced kit), which can be downloaded and installed on any supported client operating system or used directly on the server. The connection method between EM CLI and an Oracle Management Server (OMS) is the same regardless of the installation location of EM CLI. Installation instructions for the Advanced Kit are covered in Chapter 2.

The scripting option of EM CLI refers to both scripting and interactive modes. In either of these modes EM CLI expects the content of the scripts or the commands entered in interactive mode to be in Python syntax. To connect from EM CLI to Enterprise Manager in interactive mode, type the command login(username='sysman', password='foobar'). This command is a call to a Python function.

The samples in this section are the same code examples used in Chapter 6 and are all written in the Python programming language. While the samples in the previous section used the operating system shell for all of their scripting functionality (i.e., variables, for loops, if then else, etc.), the samples in this section will use EM CLI and its Jython shell for everything. Because these samples don’t rely on any shell scripting functionality, they can be used on any platform supported by EM CLI.

Simple Logon Script (start.py)

The code sample below can be copied directly into a text file. It is used to set some important session properties and to establish a secure connection between the EM CLI client and the OMS to which it is connecting. Before using this script, the variables myurl, myuser, and mypass will need to be updated for your environment:

from emcli import *

myurl = 'https://em12cr3.example.com:7802/em'
mytrustall = 'TRUE'
myoutput = 'JSON'
myuser = 'sysman'
mypass = 'foobar'

set_client_property('EMCLI_OMS_URL', myurl)
set_client_property('EMCLI_TRUSTALL', mytrustall)
set_client_property('EMCLI_OUTPUT_TYPE', myoutput)
print(login(username=myuser, password=mypass))

The start.py script can be used in both scripting and interactive modes. In scripting mode, the script could be executed directly from EM CLI using the command emcli @start.py. The result would either succeed or fail in establishing a connection between EM CLI and an OMS. Using this script alone would not be very useful unless you just wanted to see the confirmation that the connection can be made.

start.py is commonly called from other scripts, or when in interactive mode, from the EM CLI Jython command-line interface (not to be confused with command-line mode). Calling start.py from another script is done by importing the script as a module.

For example, a script called sync.py is called in scripting mode with the command emcli @sync.py. Before the commands can be executed, a connection must be established between EM CLI and an OMS. If the start.py script is in a directory that is included in JYTHONPATH, the logon script can be called as the first command with import start.

Image Note  JYTHONPATH is a shell environment variable that will be used by EM CLI to establish all of the directories to be searched when importing modules. To add a directory, supplement the variable according to the shell standards, similar to how a directory would be added to the PATH environment variable.

An alternative would be to execute the start.py in scripting mode using the command emcli @start.py and then call the sync.py (import sync) script as the last line in start.py. This method would assume that sync.py is located within the searchable path of the JYTHONPATH environment variable.

When using interactive mode, the start.py script must be in the searchable path of JYTHONPATH and be called with import start. The logon is now established for the life of the current interactive session or until the logon is implicitly (expired timeout) or explicitly (using the logout() function) dissolved.

Many Enterprise environments discourage or do not allow scripts to contain credential passwords. The start.py script can be slightly modified to take advantage of Python’s capability to read external files, as shown in the next example.

Secure Logon Script (secureStart.py)

start.py has a major flaw when it comes to security, as it contains a credential password. secureStart.py, however, has the same capability as start.py to establish a connection between EM CLI and an OMS, without revealing the credential password in the script. The script instead opens a file from the filesystem that contains the password and reads the password into a variable. It then uses the contents of this variable as the credential password in the login() function.

secureStart.py is used in the same way as start.py. However, there are additional requirements. The first requirement is to create a file on a filesystem accessible from EM CLI that contains only the credential password in plain text. Secure this file with permissions appropriate for your environment. In addition to updating the myurl and the myuser script variables to match your environment, the mypassloc script variable needs to be changed to the full path location of the file containing the credential password. Take a look at the following:

from emcli import *

myurl = 'https://em12cr3.example.com:7802/em'
mytrustall = 'TRUE'
myoutput = 'JSON'
myuser = 'sysman'
mypassloc = '/home/oracle/.secret'

set_client_property('EMCLI_OMS_URL', myurl)
set_client_property('EMCLI_TRUSTALL', mytrustall)
set_client_property('EMCLI_OUTPUT_TYPE', myoutput)

myfile = open(mypassloc,'r')
mypass = myfile.read()

print(login(username=myuser, password=mypass))

The logon scripts only establish a connection between EM CLI and an OMS. They do not have any effect on the Enterprise Manager targets. The remaining samples in this section demonstrate how to manipulate targets using interactive or scripting modes.

Update Target Properties Commands (updatePropsFunc.py)

The updatePropsFunc.py script contains the commands needed to update the properties of Enterprise Manager targets. These commands can be copied individually into an EM CLI interactive session after establishing a logon. The full sample can also be put into a script and executed directly (a logon will need to be established first) with EM CLI in scripting mode using the command emcli @updatePropsFunc.py. This sample includes comments (lines beginning with the hash character) about the script commands that should be included when copying to a script. In EM CLI (as well as in Python and Jython), any line beginning with a hash character is ignored.

Image Note  View the logon samples at the beginning of this section for information on how to establish a logon in scripting or interactive mode.

from emcli import *
import re

# Regular expression applied to target name to filter target list
# '.*' includes all targets
# '^orcl' includes all targets that begin with 'orcl'
# '^em12cr3.example.com$' includes target
#        with the exact name 'em12cr3.example.com'
myfiltermatch = '.*'

# Dictionary object containing the property names and values
#        to be applied to the target list
myprops = {'LifeCycle Status':'Development', 'Location':'COLO'}

# When debug is enabled, commands will be printed but not executed
debug = True

# Delimiter should be something that will not appear
#        in any target name
mydelim = '@'
mysubsep = 'property_records=' + mydelim

# Compile the target name filter
myreg = re.compile(myfiltermatch)

# Retrieve the full target list from the OMS
myobj = get_targets().out()['data']

# Loop through the full target list
for targ in myobj:
    # If the target name filter applies...
    if myreg.search(targ['Target Name']):
        myproprecs = targ['Target Name'] + mydelim + 
                     targ['Target Type'] + mydelim

        # Loop through the target properties dictionary
        #         for each target
        for propkey, propvalue in myprops.items():
            myproprecprops = propkey + mydelim + propvalue

            # If debug is True, print the command to screen
            #           without executing
            if debug:
                mycommand = 'set_target_property_value(' + 
                            'subseparator="' + mysubsep + 
                            '", property_records="' + 
                            myproprecs + 
                            myproprecprops + '")'
                print(mycommand)

            # If debug is not True, print a message
            #         and execute command
            else:
                print('Target: ' + targ['Target Name'] + 
                      ' (' + targ['Target Type'] + 
                      ') Property: ' + propkey + 
                      ' Value:    ' + propvalue)
                set_target_property_value(
                subseparator=mysubsep,
                property_records=myproprecs + myproprecprops)

Update Target Properties Class (updateProps.py)

The updateProps.py script contains a couple of import statements and a single class definition. This script does not contain any commands that are executed directly. Therefore, it would not be useful to execute this script directly (i.e., emcli @updateProps.py). The proper use would be to import the script as a module along with a logon script in interactive mode, then execute commands using the class and its functions. In scripting mode, an execution script would be created containing the commands that use the class and its functions. Import statements for updateProps.py and an import statement for a logon script would appear prior to any command executions.

To demonstrate this, create a script called changeTargProps.py. This script will be used to change target properties that use the updateProps() class. The environment in this example requires that the credential password not be contained in the executing script; therefore, the secureStart.py logon script will be used to establish a logon. The first two lines of changeTargProps.py will be import statements:

import secureStart
import updateProps

At this point in the execution of the script, there should have been a successful logon between EM CLI and the OMS, and the updateProps() class should have been imported. The rest of the commands in the script use the class functions to update the properties of a target:

# Create an instance of the class.
myinst = updateProps.updateProps()

# Set a single property to be applied.
myinst.props({'LifeCycle Status':'Development'})

# Include only host targets with the exact name em12cr3.example.com.
myinst.filt(namefilter='^em12cr3.example.com$', typefilter='^host$', show=True)

# Update the currently defined target list to the currently defined properties.
myinst.setprops(show=True)

This complete script could now be called in scripting mode using the command emcli @changeTargProps.py. The script would update the Lifecycle Status property of the em12cr3.example.com host target in Enterprise Manager to Development. Copying the commands from the sample into an EM CLI interactive session would have the same effect.

The functionality of updateProps() can be as simple or as complex as the situation requires. The examples below show additional methods of using updateProps(). The functionality of each example is explained using comments. Including the comments with the commands allows them to be copied with the commands into a script:

# Set multiple properties to be applied.
myinst.props({'LifeCycle Status':'Development', 'Location':'COLO', 'Comment':'Test EM'})

# Show the currently defined properties to be applied.
print(myinst.propdict)

# Include only host or agent targets that start with em12cr3.example.com.
myinst.filt(namefilter='^em12cr3.example.com', typefilter='^host|oracle_emd$')

# Include only agent targets.
myinst.filt(typefilter='^oracle_emd$')

# Include only targets managed by the em12cr3.example.com:3872 agent.
myinst.filt(agentfilter='^em12cr3.example.com:3872$')

# Include only host targets that start with EM, end with Service
# and have a single word between EM and Service.
myinst.filt(namefilter='^EMs+S+s+Service$')

# Create an instance of the class, define the properties
# to be applied and specify the target list filters in a single command.
myinst = updateProps.updateProps(namefilter='^orcl', typefilter='oracle_dbsys',
agentfilter='em12cr3.example.com:3872', propdict={'LifeCycle Status':'Development'})


# Clear all filters which resets the instance to include all targets.
myinst.filt()

# Show the currently defined target list and each target's currently
# defined properties for the myinst instance.
myinst.show()

# Update the currently defined target list to the currently defined
# properties without reprinting the target and target properties list.
myinst.setprops()

# Apply a property update using the class without creating an instance.
updateProps.updateProps(
    namefilter='^orcl',
    typefilter='oracle_dbsys',
    agentfilter='em12cr3.example.com:3872',
    propdict={
              'LifeCycle Status':'Production',
              'Location':'DC1'}
    ).setprops(True)

The sample below is the updateProps.py script. The updateProps() class is heavily commented to explain the functionality of its individual components and its purpose as a whole. Additional detail about this class can be found in Chapter 6:

import emcli
import re
import operator

class updateProps():
    """
       The updateProps() class is used in conjuction with
       EM CLI and  allows the user to apply a defined set
       of target properties to a target list filtered at
       multiple levels with regular expressions. These
       target list filter levels include the target name,
       the target type, and the parent agent name. The
       properties can be applied to the targets using the
       class directly or using an instance of the class.

       The filtered list can be specified:
         - as class parameters and have the defined
           properties applied directly to them
         - as class parameters when creating an instance
           of the class
         - with the filt() function as part of an instance

       The defined set of target properties can specified:
         - as the class dictionary parameter 'propdict'
           and have the defined properties applied
           directly to the target list
         - as the class dictionary parameter 'propdict'
           when creating an instance of the class
         - with the props() function as part of an instance
    """
    def __init__(self, agentfilter='.*', typefilter='.*',
                 namefilter='.*', propdict={}):
        self.targs = []
        self.reloadtargs = True
        self.props(propdict)
        self.__loadtargobjects()
        self.filt(agentfilter=agentfilter, typefilter=typefilter,
                  namefilter=namefilter)
    def __loadtargobjects(self):
        """
           __loadtargobjects() queries the OMS for the full
           target list. The target list is then cached in the
           instance variable 'fulltargs' and each target's
           corresponding properties are assigned to the
           'targprops' instance variable. These variables
           are refreshed only when target properties have been
           applied.

           This function is called by other functions and
           should never be called directly.
        """
        if self.reloadtargs == True:
            self.reloadtargs = False
            self.fulltargs = 
              emcli.list(resource='Targets').out()['data']
            self.targprops = 
              emcli.list(resource='TargetProperties'
                        ).out()['data']
    def props(self, propdict):
        """
           props() can be called from an instance directly or
           will be called by __init__() when defining the
           instance or using the class directly. This function
           defines a dictionary object of the property names
           and values that will be applied to the defined
           target list.
        """
        assert isinstance(propdict, dict),
               'propdict parameter must be ' + 
               'a dictionary of ' + 
                '{"property_name":"property_value"}'
        self.propdict = propdict
    def filt(self, agentfilter='.*', typefilter='.*',
             namefilter='.*',
             sort=('TARGET_TYPE','TARGET_NAME'), show=False):
        """
           filt() can be called from an instance directly or
           will be called by __init__() when defining the
           instance or using the class directly. This function
           limits the target list by only including those targets
           whose properties match the defined filters.

           This function accepts the following parameters:
             agentfilter - regular expression string applied
               to the parent agent of the target
             typefilter - regular expression string applied
               to the target type value
             namefilter - regular expression string applied
               to the target name value
        """
        self.targs = []
        __agentcompfilt = re.compile(agentfilter)
        __typecompfilt = re.compile(typefilter)
        __namecompfilt = re.compile(namefilter)
        self.__loadtargobjects()
        for __inttarg in self.fulltargs:
            if __typecompfilt.search(__inttarg['TARGET_TYPE'])
               and __namecompfilt.search(
                   __inttarg['TARGET_NAME'])
               and (__inttarg['EMD_URL'] == None or
               __agentcompfilt.search(__inttarg['EMD_URL'])):
                self.targs.append(__inttarg)
        __myoperator = operator
        for __myop in sort:
            __myoperator = operator.itemgetter(__myop)
        self.targssort = sorted(self.targs, key=__myoperator)
        if show == True:
            self.show()
    def show(self):
        """
           show() can be called from an instance directly or
           as a parameter from some of the other functions.
           Prints a neatly formatted display of the target name
           and type along with all of the target's currently
           defined property names and values.
        """
        print('%-5s%-40s%s' % (
              ' ', 'TARGET_TYPE'.ljust(40, '.'),
              'TARGET_NAME'))
        print('%-15s%-30s%s %s ' % (
              ' ', 'PROPERTY_NAME'.ljust(30, '.'),
              'PROPERTY_VALUE', '=' * 80))
        for __inttarg in self.targssort:
            print('%-5s%-40s%s' % (
                  ' ', __inttarg['TARGET_TYPE'].ljust(40, '.'),
                  __inttarg['TARGET_NAME']))
            self.__showprops(__inttarg['TARGET_GUID'])
            print('')
    def __showprops(self, guid):
        """
           __showprops() prints the target properties for the
           target with the unique guid matching the 'guid'
           variable passed to the function. This function is
           called by the show() function for each target to
           print out the corresponding properties of the target.

           This function is called by other functions and
           should never be called directly.
        """
        self.__loadtargobjects()
        for __inttargprops in self.targprops:
            __intpropname = 
              __inttargprops['PROPERTY_NAME'].split('_')
            if __inttargprops['TARGET_GUID'] == guid and
               __intpropname[0:2] == ['orcl', 'gtp']:
                print('%-15s%-30s%s' %
                      (' ', ' '.join(__intpropname[2:]).ljust(
                       30, '.'),
                       __inttargprops['PROPERTY_VALUE']))
    def setprops(self, show=False):
        """
           setprops() is called directly from the class or
           from an instance and calls the EM CLI function that
           applies the defined set of properties to each target
           in the filtered list of targets. The 'show' boolean
           parameter can be set to True to call the show()
           function after the properties have been applied.
        """
        assert len(self.propdict) > 0,
               'The propdict parameter must contain ' + 
               'at least one property. Use the ' + 
               'props() function to modify.'
        self.reloadtargs = True
        __delim = '@#&@#&&'
        __subseparator = 'property_records=' + __delim
        for __inttarg in self.targs:
            for __propkey, __propvalue
                in self.propdict.items():
                __property_records = __inttarg['TARGET_NAME'] + 
                  __delim + __inttarg['TARGET_TYPE'] + 
                  __delim + __propkey + __delim + __propvalue
                print('Target: ' + __inttarg['TARGET_NAME'] +
                      ' (' + __inttarg['TARGET_TYPE'] +
                      ') Property: '
                      + __propkey + ' Value: ' +
                        __propvalue + ' ')
                emcli.set_target_property_value(
                  subseparator=__subseparator,
                  property_records=__property_records)
        if show == True:
            self.show()

__________________________

1http://www.symantec.com/cluster-server.

2Members on a database server typically include databases and listeners using the same Oracle home. The drives related to these targets are all members of the group. Filesystems containing the Oracle base, the archive destination, the oradata filesystems, and other related data are all included in the fail-over group.

3In spite of its title, relocate_target verb does not physically relocate any targets. Its sole purpose is to transfer monitoring and metrics collection from one agent to another.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.118.2.240