By Ray Smith
Oracle Enterprise Manager Command Line Interface (EMCLI) performs OEM tasks without clicking through the GUI console. This brief paper will introduce general concepts of EMCLI and illustrate its use.
Technical Background
Architecture
Oracle Management Service (OMS) is the heart of OEM 12c Cloud Control. The OMS is a J2EE application running on a dedicated Fusion server. An EMCLI extension runs concurrently with the console and upload management services to handle command-line calls to the OMS, acting as a headless OMS. It performs the same tasks but returns text streams instead of pretty pictures. Each EMCLI command is exercised in the EMCLI Java module through the use of verbs.
Verbs
Today there are 333 EMCLI verbs, and Oracle continues to expose more of them as users request them. Each verb is well-documented in Oracle Document 17786-02 and at the command line using this syntax:
EMCLI -help
EMCLI –help <verb>
You can also refer to the online reference through the setup drop-down in OEM, as shown in Figure 1.
Figure 1
The documentation clearly provides the list of required and optional parameters for each verb, with an example for nearly all verbs. The trick, of course, is turning this knowledge into something useful.
Working with EMCLI
The EMCLI utility is invoked by calling it by name, just like SQLPLUS, EXPDP, RMAN and other Oracle utilities. Unlike sqlplus, EMCLI does not require a subshell1 when used in a shell script. You simply call it by name like any other UNIX utility (Figures 2 and 3).
Figure 2
Figure 3
Login and Logout
Basic EMCLI verbs help, setup and status don’t require authentication with OMS because they relate to the EMCLI utility itself. Any other commands require a login and, of course, a logout when your session is complete.
oracle@myoemserver> emcli login –user=sysman –pass=abc123!
oracle@myoemserver> emcli logout
Targets, Target Types and EMCLI
Targets are the key identifier in OEM. Databases, hosts, listeners, administrators and OEM roles are all target types. Each database name, host name and listener name are unique targets of a type. EMCLI relies heavily on these relationships to determine what to do. Notice that the target types for Oracle products (oracle_database, oracle_listener, f.e.) are very specific.
host
j2ee_application
metadata_repository
oracle_apm
oracle_beacon
oracle_database
oracle_dbsys
oracle_emd
oracle_emrep
oracle_em_service
oracle_home
oracle_ias_farm
oracle_listener
oracle_oms
oracle_oms_console
oracle_oms_pbs
rac_database
weblogic_domain
weblogic_j2eeserver
Discovery of specific target names can be filtered by target type:
oracle@myoemserver> emcli get_targets –target=oracle_database
0 Up oracle_database gold
0 Up oracle_database bronze.world
0 Down oracle_database sandbox_db
Target Names and the Discovery Process
In the previous example, you may have noticed that one of the database names (bronze.world) included a suffix and the other two did not. This difference is the result of the automated target discovery process that the EM agent performs if you don’t manually discover database targets in the 12c console.
The automated discovery process runs like this:
1. The agent looks at oratab for Oracle homes.
2. The agent then looks for cluster-ready services that are not present in oratab.
3. For each Oracle home, the agent polls each listener for related database service names either through lsnrctl or by parsing the listener.ora file.
4. The results of this discovery are saved in the OEM repository exactly as they are found in the listener or the clusterware.
Discovery Consequences
The EMCLI tasks you perform against database targets must use the specific target name, so you need to query the repository (via OMS through EMCLI) for the exact answer. Let’s walk through some examples to turn that into knowledge into something you can use.
Example 1: Finding the exact name of a database target
OEM selects a unique name for each registered database target. For reasons beyond the scope of this paper3, the specific name of a database target may be qualified with the host name (or not) and stored as upper or lowercase without a discernible reason. Even databases created from cloned virtual machines can display different name styles. Manipulating the target database with EMCLI requires an exact match for the target name, so every EMCLI shell scripts must use the exact unique target name from the repository.
Step 1 – Consult the manual
A visit to the documentation is the first step in any EMCLI exercise. Most verbs to query the repository start with a “get.” We need specific information about EM targets so we’ll use get_targets4 and filter it with -targets and -format parameters to define our selection.
Step 2 – Select output format
Query results can be returned in one of three predefined layouts or in user-defined layouts where you select the row and column separators. The
pretty format aligns the column headings with the content, so it makes a good choice for reports. The script and csv formats are convenient for shell scripts because they are separated by spaces and commas, respectively. The script format is useful with awk and csv lends itself to the cut command, particularly if grep-out the header row.
oracle@myoemserver> emcli get_targets –target=oracle_database –
format=”name:pretty”
Status
ID Status Target Type Target Name
0 Up oracle_database gold
0 Up oracle_database bronze.world
0 Down oracle_database sandbox_db
oracle@myoemserver> emcli get_targets –target=oracle_database –
format=”name:script”
Status ID Status Target Type Target Name
0 Up oracle_database gold
0 Up oracle_database bronze.world
0 Down oracle_database sandbox_db
oracle@myoemserver> emcli get_targets –target=oracle_database \
–format=”name:csv” | grep –v “Status”
0,Up,oracle_database,gold
0,Up,oracle_database,bronze.world
0,Down,oracle_database,sandbox_db
oracle@myoemserver> emcli get_targets –target=oracle_database –
format=”name:csv” \
| grep –i “gold” | cut –d, -f4
oracle@myoemserver> gold
Step 3 – Build that query into a reusable shell script function
You may choose to include this simple query in each of your EMCLI shell scripts, but building it into a scalable script function reduces the maintenance, removes one failure mode from each use (because this module is pre-tested) and increases the readability of your shell scripts. Let’s walk through the process.
Step 3A – Handle edge cases
An essential element of any UNIX program6 is the ability to handle failures quickly and clearly. So the first step in building an industrial strength script from the get_targets snippet is to wrap it in clear messages to the user (or log file) at each step (Figure 4).
Figure 4
Step 3B – Make it into a shell script function
Creation and application of shell script functions for bash and Korn shells consist of using the keyword function, giving the function a name, and wrapping the code inside braces {} as shown in Figure 5.
Figure 5
The function is executed inside your shell script simply by calling by name, as you’ll see later in this article.
Modularity Within a Script
In the example below, files will be duplicated from a source directory to a destination directory. A list of files is created for each source directory and then the files in that list are copied to the source directory (Figure 6).
Figure 6
Step 4 – Store the function in a function library file
Efficient coding practice uses modules, like shell functions, whenever possible. You can extend that practice by saving common functions in function libraries whenever identical code will be used by more than two scripts. Sourcing the function library loads the file contents (functions) into memory. The functions can then be called any time during your session.
In addition to the obvious advantage of editing a single copy of the function for every use in your environment, your shell scripts themselves can be significantly simpler as we’ll see in the next section.
Example 2: Blackout scripts
OEM blackouts suspend alerting for a specific target during a blackout period. This can be particularly useful during database or host maintenance. The target continues to be monitored, but you won’t be paged for a planned outage.
Creating a blackout in the console requires a minimum click-through on six console screens. Fortunately, anything you can define through those screens can also be managed directly from a shell script.
Consider the situation where a training database is refreshed/reset by restoring a cold backup. It happens every night and is scheduled through cron. The entries might consist of a series of calls, first to enable a blackout on the “gold” database in this example, the restore is executed and then blackout is killed off.
25 19 * * * /scripts/oem/create_blackout.sh gold
30 19 * * * /scripts/refresh/restore_training_baseline.sh gold
25 20 * * * /scripts/oem/end_blackout.sh gold
Step 1 – Consult the manual
Three verbs with very intuitive names are applied to manage blackouts: create_blackout, stop_blackout and delete_blackout. Each of these blackout verbs uses a common parameter: blackout_name.
Blackouts run as database jobs in your repository database, so this trio of verbs defines, starts, stops and deletes blackout jobs in OEM.
Step 2 – Write the core EMCLI commands
The create_blackout verb has the capability to set any of the values you can set from the OEM console, but a minimum of four values should be provided. Those parameters are described in Table 1. Also, see the code in Figure 7.
Table 1
Figure 7
Step 3 – Functionalize the EMCLI code
Robust shell scripts handle expected situations during execution, and the create_blackout function is no exception. (See Figure 8)
Issue 1 – Determining the exact target name
Each blackout is for a specific target or groups of targets, so we’ll apply the GetTargetNames function we create earlier to set the name for us.
Issue 2 – Existing blackouts
When you create a blackout using a formula in a shell script, you have the potential for blackout conflicts. When this conflict arises, we can either exit politely and hope that enough time remains on the last blackout or rebuild the blackout to ensure coverage.
Issue 3 – Trust
Echoing status to a log or to the screen provides the assurance that the script performed as expected.
Figure 8
Step 4 – Build the shell script to create the blackout (Figure 9)
Figure 9
Process
1. Both of the functions we’ve created are stored in a common file called /scripts/oem/EMCLI_functions.lib in this example. Sourcing the library loads the functions into your environment for use.
2. This script can either be run interactively or using cron. The database name must be passed to the script either (in this example) as a command line variable or through response to a prompt. The if statement required to fail-out when ${thisSID} is null has been take-n out of this example for clarity — your final script should include it.
3. The variable BO_NAME11 is set based on the value of thisSID.
4. The function CreateBlackout is invoked.
5. The ExitCleanly function consists of temporary file cleanup and logging out of your EMCLI session.
Step 5 – Ending the blackout
Four parameters were required to create a blackout, but only the name is required to stop and delete the blackout. Blackouts must be stopped before being deleted, because the blackout is an OMS repository job.
The wrapper script for this function is identical to the create_blackout script, but this script submits the following function EndBlockout for CreateBlackout in the start script (See Figure 10).
Figure 10
Extensibility
The crontab entry illustrated earlier relied on best-guess timing. The blackout creation script was scheduled to run a few minutes before the restore script kicks off, and the script to end the blackout was scheduled to run about an hour later.
Placing the CreateBlackout and EndBlackout scripts in a function library allows those two tasks to be integrated within any of your shell scripts instead of separate script executions. Use the same technique illustrated in the emcli_start_blackout.ksh script to source the function library at the beginning of the restore script, and call those two functions from inside the script. Apply this to any script that requires OEM blackout management for seamless, integrated operations.
Example 3: Handling Planned Outages
Scheduled maintenance events provide another opportunity to schedule blackouts in a slightly different manner, using information from the EM agent to dynamically generate script.
The Right Tool for the Job
It’s very tempting to use EMCLI as the one-size-fits-all tool once you become familiar with its features, but its flexibility starts to shine when you combine EMCLI with other data sources.
The EM agent is controlled and queried through the emctl utility. You can quickly determine the targets monitored by the local agent using emctl.
oracle@demohost> emctl config agent gettargets
[agent12g1_1_demohost, oracle_home]
[BRONZE.WORLD, oracle_database]
[demohost.com, host]
[demohost.com:3872, oracle_emd]
[LSNRBRONZE_demohost.com, oracle_listener]
[LSNRSILVER_demohost.com, oracle_listener]
[OraDb11g_home1_2_demohost, oracle_home]
[SILVER, oracle_database]
You can quickly turn those results into a list of database and listener targets to blackout with simple grep statement for the oracle_% target types and apply a little creative “cutting” to create two target lists for the databases and listeners.
oracle@demohost> emctl config agent listtargets | grep oracle_database \
| cut –d[ -f2 | cut –d, –f1 > databases.lst
oracle@demohost> cat databases.lst
BRONZE.WORLD
SILVER
oracle@demohost> emctl config agent listtargets | grep oracle_listener \
| cut –d[ -f2 | cut –d, –f1 > listeners.lst
oracle@demohost> cat listeners.lst
LSNRBRONZE_demohost.com
LSNRSILVER_demohost.com
The argfile Verb
Batch or list processing for multiple consecutive EMCLI commands is captured in the argfile verb. The syntax is quite simple:
oracle@demohost> emcli argfile /fully_qualified/path/filename.lst
All of the verbs listed in the argfile are executed in a single connection to the OMS server and process very efficiently. Let’s walk through the process of generating and executing two argfiles to start and stop blackouts for the database and listener targets from the example above.
touch blackout_start.cmd
touch blackout_end.cmd
export BONAME=GENERATED_BLACKOUT
echo “create_blackout –name=${BONAME} ” >>blackout_start.cmd
for thisDB in `cat databases.lst`; do
echo ” –add_targets=${thisDB}:oracle_database ” >>blackout_start.cmd
done
for thisLSNR in `cat listeners.lst`; do
echo ” –add_targets=${thisLSNR}:oracle_listener ” >>blackout_start.cmd
done
echo “ -schedule=duration::360;tzinfo:specified;tzregion:America/Chicago ”
>>blackout_start.cmd
echo “ -reason=Scripted blackout for maintenance” >>blackout_start.cmd
echo “stop_blackout –name=${BONAME}” >>blackout_end.cmd
echo “delete_blackout –name=${BONAME}” >>blackout_end.cmd
The loops in that short script generate the argfiles blackout_start.txt and blackout_end.txt.
oracle@demohost> cat blackout_start.cmd
create_blackout –name= GENERATED_BLACKOUT \
–add-targets=BRONZE.WORLD:oracle_database \
–add-targets=SILVER:oracle_database \
–add-targets= LSNRBRONZE_demohost.com:oracle_listener \
–add-targets= LSNRSILVER_demohost.com:oracle_listener \
-schedule=duration::360;tzinfo:specified;tzregion:America/Chicago \
-reason=Scripted blackout for maintenance
oracle@demohost> cat blackout_end.cmd
stop_blackout –name= GENERATED_BLACKOUT
delete_blackout –name= GENERATED_BLACKOUT
Executing these blocks consists of invoking emcli with the argfile command. Notice that each command starts with a verb and not “emcli.”
oracle@demohost> emcli argfile blackout_start.txt
< Do some work on the host>
oracle@demohost> emcli argfile blackout_end.txt
Summary
OEM 12c command line interface provides a convenient means of automating tasks on the command line or inside shell scripts. The first step in implementing EMCLI in your environment is to download a copy of the reference document. A comprehensive list of verbs is also included online and can be accessed through the console. The examples provided here provide a starting point. My Oracle Support now features community interaction for challenges you encounter. Click on the Communities tab to subscribe to the Enterprise Manager communities (Figure 11).
Figure 11
About the Author
Ray Smith is actively engaged as a volunteer for IOUG. He has served on COLLABORATE and Oracle OpenWorld, and is on the SELECT Journal Editorial Board. He currently works as a senior Oracle DBA/technologist for Portland General Electric in Portland, Ore. He is also an Oracle ACE.