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
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.
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?
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.
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.
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.
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.
18.118.2.240