#!/usr/local/bin/perl # # $Header: emdb/sysman/admin/discover/oracledb.pl /st_emdbsa_11.2/2 2009/02/03 18:17:34 shasingh Exp $ # # oracledb.pl # # Copyright (c) 2002, 2009, Oracle and/or its affiliates.All rights reserved. # # NAME # oracledb.pl - # # DESCRIPTION # # # NOTES # # # MODIFIED (MM/DD/YY) # shasingh 12/07/08 - Choose service name as of database name # vgoli 12/02/08 - fix bug 7602853: conditionalize oraProcExists in # isValidSid # tpalgudi 11/13/08 - Bug#4067458 fix # mkiran 11/03/08 - 7360354: Accurately parse o/p of lsnrctl services # shasingh 09/10/08 - # nachen 06/19/08 - XbranchMerge nachen_bug-7144603 from st_emdbsa_11.1 # nachen 06/06/08 - fix internal references security issue # prakgupt 05/12/08 - fix bug 6792454 - check existence of envJavaHome in # shasingh 02/07/08 - added discovery hint params # shasingh 06/18/07 - bug 6136655: unset SRVM_TRACE env variable # execute command # shasingh 05/13/07 - bug 5648922: add FQDN to listener host # mkiran 03/09/07 - 4774824: Unset LD_LIBRARY_PATH on HP-UX # mkiran 08/11/06 - 4774824: Unset LD_LIBRARY_PATH on HP-UX # xuliu 07/13/05 - CLUSTER_NAME # jstone 06/02/05 - add use strict # xuliu 03/22/05 - check instance_number for rac # jstone 03/31/05 - fixes for MAC OS X # xuliu 11/10/04 - don't print rac target if not in cluster # dkapoor 11/11/04 - 3772840:update correct listener home # xuliu 11/10/04 - OMSENV_CLUSTER_NAME # xuliu 10/28/04 - 10gr2 misc # xuliu 10/22/04 - new rac_database metadata # dkapoor 10/15/04 - fix bug 3872639 # dkapoor 08/12/04 - touch for 10.2SA testing # dkapoor 06/16/04 - no pass for ASM # xuliu 06/04/04 - fix 3667625 for rac # xuliu 05/13/04 - bug 3626488 # xuliu 05/12/04 - bug 3468650 # xuliu 03/18/04 - fix 3495276 # mbhoopat 03/10/04 - linux port # xuliu 03/01/04 - workaround 3469118 # xuliu 02/18/04 - fix 3450484: disable err of spfile conversion # dkapoor 02/17/04 - fix dynamic sid on NT # xuliu 02/12/04 - fix 3434862 # dkapoor 01/19/04 - use containsFile # dkapoor 01/23/04 - don't use TNS_ADMIN env in windows # xuliu 01/26/04 - fix 3383117 for NT # dkapoor 12/09/03 - unset ORA_NLS vars # dkapoor 12/02/03 - check for soft link tnsadmin and ohome # xuliu 11/24/03 - fix 3264493 # dkapoor 11/15/03 - fix 10g listener # xuliu 11/11/03 - fix 3178713 # dkapoor 11/05/03 - fix 3220691 # dkapoor 10/31/03 - add more logging # dkapoor 10/27/03 - add logging # dkapoor 10/24/03 - fix bug#3202471 # dkapoor 10/03/03 - use db_unique_name # xuliu 08/19/03 - fix 3106024 # xuliu 08/05/03 - fix 3079354 # xuliu 07/23/03 - srvctl version chg # xuliu 07/18/03 - use DiscoveryWarning tag # dkapoor 05/28/03 - use initParam subs for local listener # dkapoor 05/15/03 - check pmon # dkapoor 05/08/03 - put host for rac db # dkapoor 05/07/03 - use address host,filter pre 8.1 dbs # dkapoor 04/17/03 - move parsing code to net area # xuliu 03/17/03 - fix service name # xuliu 01/06/03 - logging for RAC # xshen 12/22/02 - separate osm_instance targets from db # xuliu 12/13/02 - rac tgt naming # xuliu 12/12/02 - disable cluster tgt printing & more robust host equivalence test # dkapoor 11/14/02 - port to NT # dkapoor 11/12/02 - filter out PLSEXtPROC sid # dkapoor 11/02/02 - add 1521 port for first OHome for Port Table # dkapoor 10/30/02 - fix 2649537 # dkapoor 10/10/02 - make a union of sids found dynamically # xuliu 10/07/02 - comment serviceName error for non-rac case # xuliu 10/01/02 - redirect err to pipe in executeCommand # xuliu 09/25/02 - refine rac discovery logic # xuliu 08/30/02 - serviceName logic # xuliu 08/22/02 - find cluster # xuliu 08/20/02 - rac & service_name discovery # dkapoor 07/31/02 - use dbsnmp as default user # dkapoor 07/31/02 - remove perltrace # dkapoor 07/22/02 - add listener disc. and port info # kduvvuri 04/04/02 - remove debug statement.. # kduvvuri 04/04/02 - consider ORATAB environment variable, if it exists.. # kduvvuri 03/07/02 - don't process sid's that have a '*' as the value.. # kduvvuri 02/11/02 - kduvvuri_cemd_programmatic_discovery_v2 # kduvvuri 02/05/02 - Creation # use strict; use Config; use Cwd; my ($emdRoot,$hostName,$crsHome) = @ARGV; $ENV{EMDROOT} = $emdRoot; require "$emdRoot/sysman/admin/scripts/semd_common.pl"; require "$emdRoot/sysman/admin/scripts/db/db_common.pl"; require "$emdRoot/sysman/admin/scripts/db/net/listenerUtil.pl"; require "$emdRoot/sysman/admin/discover/utl/oracledbUtl.pl"; require "$emdRoot/sysman/admin/discover/utl/initParameterFileUtl.pl"; require "$emdRoot/sysman/admin/scripts/emd_common.pl"; my %RacSidConversionMap; #Discovery LOG CATEGORY my $LOG_CATEGORY = "DB_LISTENER_DISCOVERY: "; #VIP name of the local machine if in 10g cluster my $LOCAL_HOST_VIP_NAME = ""; #Cluster Name if it's in cluster my $CLUSTER_NAME = ""; #CRS Home if 10g cluster my $CRS_HOME = ""; # Hashtable contains lsnrctl versions my %lsnrctlVersions; my $elapsedSec = time(); EMD_PERL_INFO("$LOG_CATEGORY ***** Start of Database and Listener Discovery***"); #Unset ORA_NLS variables if in the environment if(defined $ENV{ORA_NLS}) { delete ($ENV{ORA_NLS}); } if(defined $ENV{ORA_NLS32}) { delete ($ENV{ORA_NLS32}); } if(defined $ENV{ORA_NLS33}) { delete ($ENV{ORA_NLS33}); } #if in Windows, remove TNS_ADMIN from the environment variable #because there is no global TNS_ADMIN in windows, we should get # from registry for each Oracle Home, that is, use getDefaultTNSAdmin if((get_osType() eq 'WIN') && defined $ENV{TNS_ADMIN}) { delete ($ENV{TNS_ADMIN}) if defined($ENV{TNS_ADMIN}); } # 4774824: Unset LD_LIBRARY_PATH on HP-UX # Reasons: # (1) To prevent 64bit sqlplus/tnslsnr from picking wrong version of .sl from # /lib during discovery on HP and fail with unsatisfied symbols. # (2) 64bit sqlplus/tnslsnr should load .sl from /lib. # /lib is prefixed to only SHLIB_PATH on HP-UX. # So, 64bit execs would unsuccessfully search for .sl in LD_LIBRARY_PATH. # Hence unsetting LD_LIBRARY_PATH here to speed up discovery. if(get_osType() eq 'HP') { delete ($ENV{LD_LIBRARY_PATH}) if defined($ENV{LD_LIBRARY_PATH}); } # bug 6136655: unset SRVM_TRACE env variable to disable srvctl and related # utilities trace log my $srvm_trc_flg = $ENV{SRVM_TRACE}; delete $ENV{SRVM_TRACE} if defined $srvm_trc_flg ; my %hintParams = (); if(defined $ENV{DISCOVERY_HINTS_AVAIL}) { my @stdins = ; foreach my $param (@stdins) { if($param =~ m/DISCOVERY_HINTS=(.*)\s*/) { %hintParams = ( split /[=,]/, $1); } } EMD_PERL_INFO("$LOG_CATEGORY discovery hints found"); while ( my ($key, $value) = each(%hintParams) ) { EMD_PERL_INFO("$LOG_CATEGORY env variable $key => $value\n"); } } my $dieh = $SIG{__DIE__} if $SIG{__DIE__}; $SIG{__DIE__}=''; eval { local $SIG{ALRM} = sub { alarm 0; my %erra = (); $erra{TimeOut}= "Discovery timed out"; print "\n"; printDiscoveryErrors(\%erra, $hostName); print "\n"; die "discovery time out"; }; alarm $hintParams{discovery_timeout} if defined $hintParams{discovery_timeout}; print "\n"; printDatabaseAndListnerTargets(); print "\n"; alarm 0; }; $SIG{__DIE__} = $dieh if $dieh; # bug 6136655: set SRVM_TRACE env variable to original value before #exiting $ENV{SRVM_TRACE} = $srvm_trc_flg if defined $srvm_trc_flg; $elapsedSec = time() - $elapsedSec; #print "Total sec=$elapsedSec\n"; EMD_PERL_INFO("$LOG_CATEGORY ***** END of Database and Listener Discovery***"); ##print discovered Oracle Database and Listener targets sub printDatabaseAndListnerTargets { my ($emdRoot,$hostName) = @ARGV; #Get Oracle Homes and Sids my ($ohomesRef,$sidsRef) = getOracleHomesAndSids(); my @oHomesWithLsnrctl; my $lsnrctl; foreach my $oracleHome (@$ohomesRef) { $lsnrctl = getListenerControl($oracleHome); if(-e $lsnrctl) { push(@oHomesWithLsnrctl,$oracleHome); } else { EMD_PERL_DEBUG("$LOG_CATEGORY $lsnrctl does not exist in $oracleHome; this home is excluded from discovery"); } } #Sort the Oracle Homes in the descending order of #its listener control version. @oHomesWithLsnrctl = sort { compareVersions(getLsnrctlVersion($b) , getLsnrctlVersion($a)) } @oHomesWithLsnrctl; $ohomesRef = \@oHomesWithLsnrctl; #filterOutBadOracleHomes($ohomesRef, $sidsRef); filterOutNotSupportedOracleHomes($ohomesRef, $sidsRef); #filter out sids from oratab without initialization or lk file on Solaris my $OSNAME = get_osType(); my $uname = ''; unless ( $OSNAME eq 'WIN' ) { chomp($uname=`/bin/uname`) || chomp($uname=`/usr/bin/uname`); } if ($uname eq "HP-UX") { $ENV{UNIX95} = "XPG4"; } if(!($OSNAME eq 'WIN')) { for my $sid (keys %$sidsRef) { my $oHome = $sidsRef->{$sid}; if (isValidSid($sid, $oHome)) { next; } delete $sidsRef->{$sid}; my $initDir = getDefaultInitFileLocation($oHome); EMD_PERL_DEBUG("$LOG_CATEGORY SID=$sid excluded from discovery as it does not have a running pmon process, \"$initDir/lk". uc ($sid) . " file or initialization file."); } } my ($clusterRef, $racInstsRefs, $errRefs) = discoverRacTargets($ohomesRef, $hostName); my %racDBHome; my %racDBPort; my %racDBLsnrHost; my %racDBSID; my %racDBServiceName; my %racDBGlbName; # delete rac database entries foreach my $racDB (@{$clusterRef->{RACDATABASES}}) { delete $sidsRef->{$racDB}; EMD_PERL_DEBUG("$LOG_CATEGORY deleting RAC db $racDB"); } # $racSidDB{$racSid} is the rac database name of the $racSid my %racSidDB; # add rac instance entries to the $sidRef foreach my $goodRacDB (keys %$racInstsRefs) { my $insts = $racInstsRefs->{$goodRacDB}; for(my $i=0; $i<@$insts; $i++) { my ($node, $sid, $ohome) = @{$insts->[$i]}; if (&equalHosts($node, $hostName)) { if (isValidSid($sid, $ohome)) { $sidsRef->{$sid} = $ohome; addToArrayIfNotExisting($ohomesRef, $ohome); $racSidDB{$sid} = $goodRacDB; } else { my $initDir = getDefaultInitFileLocation($ohome); EMD_PERL_DEBUG("$LOG_CATEGORY SID=$sid excluded from discovery as it does not have a running pmon process, \"$initDir/lk". uc ($sid) . " file or initialization file."); } } } } #Discover listeners information and dynamic SIDS configured with #listeners my ($dynamicSidsRef,$listenersRef) = discoverListenersSids($ohomesRef); # $dynamicSidsRef is of the followig form: # ( # orcl92 => # { # SERVICE_NAME => orcl92.example.com, # ORACLE_HOME => d:\oracle92\ora92, # PORT => 1234 (obtained from the first address description) # }, # orcloid => # { # SERVICE_NAME => orclServiceName, # ORACLE_HOME => d:\oracle92\test, # PORT => 1234 # }, # ) #Add/(update for) dynamic sid in the sid list obtained #from the standard location foreach my $dynmamicSid(keys (%$dynamicSidsRef)) { my $href = $dynamicSidsRef->{$dynmamicSid}; my $oHome = $href->{ORACLE_HOME}; if(!isSupportedHome($oHome)) { #dynamic db home is pre 8i, remove it from discovered db. delete $sidsRef->{$dynmamicSid}; delete $dynamicSidsRef->{$dynmamicSid}; EMD_PERL_DEBUG("$LOG_CATEGORY deleting dynamic \"$dynmamicSid\" as its Oracle Home \"$oHome\" is not supported."); next; } #if home is defined and not empty string #update the sids list if(defined $oHome && trim($oHome) ne "") { $sidsRef->{$dynmamicSid} = $oHome; EMD_PERL_DEBUG("$LOG_CATEGORY adding dynamic sid \"$dynmamicSid\" with Oracle Home \"$oHome\"."); } else { #Oracle home not found for the dynamic sid, may be on Windows if(defined $sidsRef->{$dynmamicSid}) { # sid discovered statically, update the home in the dynamic list $href->{ORACLE_HOME} = $sidsRef->{$dynmamicSid}; EMD_PERL_DEBUG("$LOG_CATEGORY sid discovered statically, update the home in the dynamic list"); EMD_PERL_DEBUG("$LOG_CATEGORY \"$dynmamicSid\" with Oracle Home \"".$href->{ORACLE_HOME}."\"."); } else { EMD_PERL_WARN("$LOG_CATEGORY discard dynamic \"$dynmamicSid\" : cannot determine its home"); } } } my @dbTargetNames; ##print database targets registered dynamically with listeners foreach my $discoveredSid (keys (%$sidsRef)) { EMD_PERL_INFO("$LOG_CATEGORY processing sid=\"$discoveredSid\""); #check if this sid id dynamically registered with any listener my $href = $dynamicSidsRef->{$discoveredSid}; if(defined $href) { EMD_PERL_DEBUG("$LOG_CATEGORY sid=\"$discoveredSid\" is found dynamically registered with a listener."); my $serviceNamesRef = $href->{SERVICE_NAME}; my $serviceName = ""; $serviceName = @$serviceNamesRef[0] if defined $serviceNamesRef; #Default to first element (mostly there would only one element) # my $addr = $href->{ADDRESSES}; #$discoveredSid is dynamically registered with a listener #Get the Best TCP port of the listener and use it for this sid. # my $port = getBestTCPPort($addr)->{PORT}; my $port = $href->{PORT}; my $lsnrHost = $href->{HOST}; ##print this sid target my ($err, $targetName); my $dbn = checkNAddToRac($hostName, $sidsRef->{$discoveredSid}, $discoveredSid, $racInstsRefs); if ($dbn ne "") { # RAC: cluster_database = true if ($dbn eq "_INVALID_SID_DETECTED_") { #let's skip this instance since we don't know its real sid #otherwise, it can produce duplicate targets EMD_PERL_DEBUG("$LOG_CATEGORY invalid RAC target: $discoveredSid:$sidsRef->{$discoveredSid}, SKIPPED"); # record the error $errRefs->{"$discoveredSid"} = "Invalid cluster database instance - couldn't find the instance_name '$discoveredSid' in oracle home '$sidsRef->{$discoveredSid}'\n"; delete $sidsRef->{$discoveredSid}; next; } $racSidDB{$discoveredSid} = $dbn; } if (defined $racSidDB{$discoveredSid}) { ($err, $targetName) = getTargetName($sidsRef->{$discoveredSid}, $discoveredSid, 1); $racDBPort{$racSidDB{$discoveredSid}} = $port; $racDBLsnrHost{$racSidDB{$discoveredSid}} = $lsnrHost; $racDBSID{$racSidDB{$discoveredSid}} = $discoveredSid; $racDBHome{$racSidDB{$discoveredSid}} = $sidsRef->{$discoveredSid}; $racDBGlbName{$racSidDB{$discoveredSid}} = &getRacDBGlbName($targetName, $racSidDB{$discoveredSid}); if($serviceName eq "") { my ($err, $serviceName) = discoveryServiceName($sidsRef->{$discoveredSid}, $discoveredSid); # record the error for now if ($err ne "") { $errRefs->{"$discoveredSid.ServiceName"} = $err; } } else # Retrive db name matching service name in case of multiple one { my $racServiceName; foreach my $servName (@$serviceNamesRef) { if($servName eq $racSidDB{$discoveredSid}) { $racServiceName = $servName; last; } } $serviceName = $racServiceName if defined($racServiceName) and $racServiceName ne ""; } $racDBServiceName{$racSidDB{$discoveredSid}} = $serviceName; if ($CLUSTER_NAME ne "") { printRACInstanceEntry($discoveredSid,$lsnrHost,$hostName,$sidsRef->{$discoveredSid}, $port, $racDBGlbName{$racSidDB{$discoveredSid}}, $serviceName); } elsif (defined($ENV{OMSENV_WARN_CLUSTER_FOUND}) && ! defined($errRefs->{"WARN_CLUSTER_FOUND"})) { $errRefs->{"WARN_CLUSTER_FOUND"} = "Unknown"; } } else { ($err, $targetName) = getTargetName($sidsRef->{$discoveredSid}, $discoveredSid); if($serviceName eq "") { my ($err, $serviceName) = discoveryServiceName($sidsRef->{$discoveredSid}, $discoveredSid); # record the error for now if ($err ne "") { #$errRefs->{"$discoveredSid.ServiceName"} = $err; } } printOracleDatabaseEntry($targetName,$discoveredSid,$lsnrHost,$hostName,$sidsRef->{$discoveredSid}, $port, $serviceName,\@dbTargetNames); } #Delete the printed database target delete $sidsRef->{$discoveredSid}; } } #Now we have non-dynamic SIDs to associate with a listener ##print Listener targets and database targets statically register with a listener my @listenerTargetNames; foreach my $listener (@$listenersRef) { EMD_PERL_INFO("$LOG_CATEGORY processing listener \"$listener->{NAME}\" from \"$listener->{FILE}\""); #Get the best TCP address of the listener my $addr = getBestTCPPort($listener->{ADDRESSES}); if(!defined $addr) { EMD_PERL_INFO("$LOG_CATEGORY listener does not have any TCP port, don't process further."); next; } #get the listener target name given its name my $targetName = getListenerTargetName($listener->{NAME},\@listenerTargetNames); ##print the listener target printListenerEntry($targetName, $listener->{FILE},$listener->{NAME}, $addr->{HOST}, $hostName, $listener->{ORACLE_HOME},$addr->{PORT}); #Get static SID list of the listener my $sidsDescs = $listener->{SID_DESC}; if(defined $sidsDescs) { #There is a static SID register with this listener foreach my $sidDesc (@$sidsDescs) { my $registerSID = $sidDesc->{SID_NAME}; #check if a static SID matches any remaining discovered #sids, so that we can match this listener with the SID foreach my $discoveredSid (keys (%$sidsRef)) { if($registerSID eq $discoveredSid) { EMD_PERL_INFO("$LOG_CATEGORY SID=$discoveredSid is statically registered with listener \"$listener->{NAME}\" from \"$listener->{FILE}\""); if(defined $addr) { EMD_PERL_DEBUG("$LOG_CATEGORY it has some address"); #$discoveredSid matches $registerSID, associate the #the best TCP address $addr with $discoveredSid. ##print the $discoveredSid database target my ($err_t, $targetName); my $dbn = checkNAddToRac($hostName, $sidsRef->{$discoveredSid}, $discoveredSid, $racInstsRefs); if ($dbn ne "") { # RAC: cluster_database = true if ($dbn eq "_INVALID_SID_DETECTED_") { #let's skip this instance since we don't know its real sid #otherwise, it can produce duplicate targets EMD_PERL_DEBUG("$LOG_CATEGORY invalid RAC target: $discoveredSid:$sidsRef->{$discoveredSid}, SKIPPED"); # record the error $errRefs->{"$discoveredSid"} = "Invalid cluster database instance - couldn't find the instance_name '$discoveredSid' in oracle home '$sidsRef->{$discoveredSid}'\n"; delete $sidsRef->{$discoveredSid}; next; } $racSidDB{$discoveredSid} = $dbn; } if (defined $racSidDB{$discoveredSid}) { ($err_t, $targetName) = getTargetName($sidsRef->{$discoveredSid}, $discoveredSid, 1); $racDBPort{$racSidDB{$discoveredSid}} = $addr->{PORT}; $racDBLsnrHost{$racSidDB{$discoveredSid}} = $addr->{HOST}; $racDBSID{$racSidDB{$discoveredSid}} = $discoveredSid; $racDBHome{$racSidDB{$discoveredSid}} = $sidsRef->{$discoveredSid}; $racDBGlbName{$racSidDB{$discoveredSid}} = &getRacDBGlbName($targetName, $racSidDB{$discoveredSid}); my ($err, $serviceName) = discoveryServiceName($sidsRef->{$discoveredSid}, $discoveredSid); # record the error for now if ($err ne "") { $errRefs->{"$discoveredSid.ServiceName"} = $err; } $racDBServiceName{$racSidDB{$discoveredSid}} = $serviceName; if ($CLUSTER_NAME ne "") { printRACInstanceEntry($discoveredSid,$addr->{HOST}, $hostName,$sidsRef->{$discoveredSid}, $addr->{PORT}, $racDBGlbName{$racSidDB{$discoveredSid}}, $serviceName); } elsif (defined($ENV{OMSENV_WARN_CLUSTER_FOUND}) && ! defined($errRefs->{"WARN_CLUSTER_FOUND"})) { $errRefs->{"WARN_CLUSTER_FOUND"} = "Unknown"; } } else { ($err_t, $targetName) = getTargetName($sidsRef->{$discoveredSid}, $discoveredSid); my ($err, $serviceName) = discoveryServiceName($sidsRef->{$discoveredSid}, $discoveredSid, $errRefs); # record the error for now if ($err ne "") { #$errRefs->{"$discoveredSid.ServiceName"} = $err; } printOracleDatabaseEntry($targetName, $discoveredSid, $addr->{HOST}, $hostName, $sidsRef->{$discoveredSid},$addr->{PORT},$serviceName,\@dbTargetNames); } #Delete the printed database target delete $sidsRef->{$discoveredSid}; } } }#End of foreach $sid (keys (%sidOhomes)) }#End of foreach $sidDesc (@$sidsDescs) }#End of if(defined $sidsDescs) }#End of foreach $listener (@$listenersRef) #Now we have SIDs which are neither dynamically registered #nor statically registered with a discovered listener EMD_PERL_DEBUG("$LOG_CATEGORY Now we have SIDs which are neither dynamically registered nor statically registered with a discovered listener"); foreach my $discoveredSid (keys (%$sidsRef)) { EMD_PERL_DEBUG("$LOG_CATEGORY get local listener for $discoveredSid"); my $addListHref = getLocalListenerAddresses( $discoveredSid,$sidsRef->{$discoveredSid}); #$discoveredSid is dynamically registered with a listener #Get the Best TCP port of the listener and use it for this sid. if(defined $addListHref) { my $addr = getBestTCPPort($addListHref); if(defined $addr) { my ($err_t, $targetName); my $dbn = checkNAddToRac($hostName, $sidsRef->{$discoveredSid}, $discoveredSid, $racInstsRefs); if ($dbn ne "") { # RAC: cluster_database = true if ($dbn eq "_INVALID_SID_DETECTED_") { #let's skip this instance since we don't know its real sid #otherwise, it can produce duplicate targets EMD_PERL_DEBUG("$LOG_CATEGORY invalid RAC target: $discoveredSid:$sidsRef->{$discoveredSid}, SKIPPED"); # record the error $errRefs->{"$discoveredSid"} = "Invalid cluster database instance - couldn't find the instance_name '$discoveredSid' in oracle home '$sidsRef->{$discoveredSid}'\n"; delete $sidsRef->{$discoveredSid}; next; } $racSidDB{$discoveredSid} = $dbn; } if (defined $racSidDB{$discoveredSid}) { ($err_t, $targetName) = getTargetName($sidsRef->{$discoveredSid}, $discoveredSid, 1); $racDBPort{$racSidDB{$discoveredSid}} = $addr->{PORT}; $racDBLsnrHost{$racSidDB{$discoveredSid}} = $addr->{HOST}; $racDBSID{$racSidDB{$discoveredSid}} = $discoveredSid; $racDBHome{$racSidDB{$discoveredSid}} = $sidsRef->{$discoveredSid}; $racDBGlbName{$racSidDB{$discoveredSid}} = &getRacDBGlbName($targetName, $racSidDB{$discoveredSid}); # use rac database name as the default service name my ($err, $serviceName) = discoveryServiceName($sidsRef->{$discoveredSid}, $discoveredSid); # record the error for now if ($err ne "") { $errRefs->{"$discoveredSid.ServiceName"} = $err; } $racDBServiceName{$racSidDB{$discoveredSid}} = $serviceName; if ($CLUSTER_NAME ne "") { printRACInstanceEntry($discoveredSid,$addr->{HOST},$hostName,$sidsRef->{$discoveredSid}, $addr->{PORT}, $racDBGlbName{$racSidDB{$discoveredSid}}, $serviceName); } elsif (defined($ENV{OMSENV_WARN_CLUSTER_FOUND}) && ! defined($errRefs->{"WARN_CLUSTER_FOUND"})) { $errRefs->{"WARN_CLUSTER_FOUND"} = "Unknown"; } } else { ($err_t, $targetName) = getTargetName($sidsRef->{$discoveredSid}, $discoveredSid); my ($err, $serviceName) = discoveryServiceName($sidsRef->{$discoveredSid},$discoveredSid); # record the error for now if ($err ne "") { #$errRefs->{"$discoveredSid.ServiceName"} = $err; } printOracleDatabaseEntry($targetName, $discoveredSid,$addr->{HOST},$hostName, $sidsRef->{$discoveredSid},$addr->{PORT},$serviceName,\@dbTargetNames); } #Delete the printed database target delete $sidsRef->{$discoveredSid}; } } } # print rac databases if ($CLUSTER_NAME ne "") { printRACDatabaseEntries($racInstsRefs, \%racDBHome, \%racDBLsnrHost, \%racDBPort, \%racDBSID, $hostName, \%racDBServiceName, \%racDBGlbName, $clusterRef); } # print the error during the discovery printDiscoveryErrors($errRefs, $hostName); } #Gets a unique listener target name sub getListenerTargetName { my ($lsnrName,$listenerTargetNames) = @_; my $counter = 0; my $retTargetName = $lsnrName; my $uniqueNotFound = 1; while($uniqueNotFound) { $uniqueNotFound = 0; if(contains($retTargetName,@$listenerTargetNames)) { $retTargetName = $lsnrName . $counter; $counter++; $uniqueNotFound = 1; } } push(@$listenerTargetNames,$retTargetName); return $retTargetName; } # Get the TCP address # prefer the one with 1521 port sub getBestTCPPort { my ($addrRef) = @_; my $tcpAddDetailRef; foreach my $addDetailRef (@$addrRef) { if(uc ($addDetailRef->{PROTOCOL}) eq "TCP" ) { $tcpAddDetailRef = $addDetailRef if (!defined $tcpAddDetailRef || trim($tcpAddDetailRef->{PORT}) eq "1521" || equalHosts($addDetailRef->{HOST}, $LOCAL_HOST_VIP_NAME)); } if((defined $tcpAddDetailRef) && trim($tcpAddDetailRef->{PORT}) eq "1521") { last; } } return $tcpAddDetailRef; } #Gets the listener info #Also gets a hashtable of port,protocol,ohome, passwords to discover dynamic sids #with port as the key sub discoverListenersSids { my ($ohomesRef) = @_; my @listeners; my %dynamicSids; my %portTable; my $parseGlobalFile = 0; my $tnsAdminDir; my $globalTnsAdminDir; my %alreadyParsed = (); if ( defined $ENV{TNS_ADMIN} ) { $globalTnsAdminDir = trim ( $ENV{TNS_ADMIN} ); if (! -d $globalTnsAdminDir ) { $globalTnsAdminDir = ""; } if($globalTnsAdminDir ne "") { $parseGlobalFile = 1; } } foreach my $oHome (@$ohomesRef) { if($parseGlobalFile ) { EMD_PERL_DEBUG("$LOG_CATEGORY Parsing listeners from TNS_ADMIN=$globalTnsAdminDir"); parseListener($ohomesRef,$globalTnsAdminDir,$oHome,\@listeners,\%portTable,\%alreadyParsed); $parseGlobalFile = 0; } $tnsAdminDir = getDefaultTNSAdmin($oHome); parseListener($ohomesRef,$tnsAdminDir,$oHome,\@listeners,\%portTable,\%alreadyParsed); } if(!defined $portTable{1521} && defined $ohomesRef->[0]) { #Update Port Table with default TCP port 1521 #and for first Oracle home my @pswd = (); my $address = { PORT=> 1521 , HOST=>$hostName, PROTOCOL=>"TCP" }; my @addresses; push(@addresses,$address); updateListenerData($ohomesRef->[0],\%portTable,\@addresses,@pswd); } updateDynamicSids(\%portTable,\%dynamicSids); return (\%dynamicSids,\@listeners); } sub parseListener { my ($ohomesRef,$tnsAdminDir,$oHome,$listeners,$portTable,$alreadyParsed) = @_; my $listenerFile = $tnsAdminDir . "/listener.ora"; if(-e $listenerFile) { my $OSNAME = get_osType(); #if we are not in Windows, check for file stat #else match the file names ignore case. if(!($OSNAME eq 'WIN')) { my ($dev, $ino) = stat $listenerFile; if(defined $alreadyParsed->{$dev,$ino}) { EMD_PERL_DEBUG("$LOG_CATEGORY $listenerFile already parsed, curr oh = $oHome"); return; } $alreadyParsed->{$dev,$ino} = $listenerFile; } else { if(containsFile($listenerFile,keys %$alreadyParsed)) { EMD_PERL_DEBUG("$LOG_CATEGORY $listenerFile already parsed, curr oh = $oHome"); return; } $alreadyParsed->{$listenerFile} = $listenerFile; } my $listenersInfo = parseOracleConfigFile($listenerFile); if(!(defined $listenersInfo)) { next; } EMD_PERL_DEBUG("$LOG_CATEGORY Listeners from $listenerFile for OH=$oHome"); my @listenerNames = getListenerNames($listenersInfo); foreach my $lsnr (@listenerNames) { EMD_PERL_DEBUG("$LOG_CATEGORY Name $lsnr"); my $addresses = getListenerAddresses($lsnr,$listenersInfo); # Xun: fix for bug 3178713 # We'll get rid of all remote addresses (defined as the address whose # host ip as returned by gethostbyname() doesn't match that of the local host # getRidOfRemoteAddresses($addresses, $hostName); if (0 == @$addresses) { EMD_PERL_DEBUG("$LOG_CATEGORY Skip $lsnr: it has no local address on host $hostName"); next; } my $sids = getStaticSIDs($lsnr,$listenersInfo); my @passwords = getPasswords($lsnr,$listenersInfo); updateListenerData($oHome,$portTable,$addresses,@passwords); #Get listener home my $lsnrOHome = getListenerHome($ohomesRef,$lsnr,$oHome,$tnsAdminDir,@passwords); EMD_PERL_DEBUG("$LOG_CATEGORY Listener [$lsnr] Ohome=$lsnrOHome"); my $listener = { NAME => $lsnr, ADDRESSES => $addresses, # where $addresses is an array reference and each entry is a hashtable # containing address parameters like PROTOCOL, HOST , PORT etc. # For example: # ( # { # PROTOCOL => TCP, # HOST => hsunnaa25 # PORT => 1234 # }, # PROTOCOL => IPC, # KEY => EXTPROC # }, SID_DESC => $sids, # where $sids is an array reference and each entry is a hashtable # containing sid parameters like SID_NAME, GLOBAL_DBNAME , ORACLE_HOME # For example: # ( # { # SID_NAME => emdw1, # ORACLE_HOME => home2 # }, # GLOBAL_DBNAME => gdbname, # SID_NAME => orcl # ORACLE_HOME => home1 # }, FILE => $tnsAdminDir, ORACLE_HOME => $lsnrOHome, # where oracle may be empty if this listener is not under an Oracle Home }; push (@$listeners,$listener); } } } #run lsnrctl for each port in the $portTable #and collect sid information in the dynamic sids sub updateDynamicSids { my ($portTable,$dynamicSids) = @_; #First update dynamic sids for 1521 if present #and do the same for rest later updateDynamicSidsForPort($portTable,$dynamicSids,1521); foreach my $port (keys %$portTable) { if($port eq 1521) { next; } updateDynamicSidsForPort($portTable,$dynamicSids,$port); } } sub updateDynamicSidsForPort { my ($portTable,$dynamicSids,$port) = @_; my $address; my $oracleHome; my $executable; my @discoveredSids; my $portInfo = $portTable->{$port}; if(!defined $portInfo) { return; } $oracleHome = $portInfo->{ORACLE_HOME}; $address = "(ADDRESS="; $address .= "(PROTOCOL=".$portInfo->{PROTOCOL}.")"; $address .= "(HOST=".$portInfo->{HOST}.")"; $address .= "(PORT=".$port.")"; $address .=")"; my $passwordList = $portInfo->{PASSWORDS}; my @commands = (); push(@commands,"set displaymode raw"); push(@commands,"services $address"); push(@commands,"exit"); my $result = getLsnrctlOutput($oracleHome,$passwordList,@commands); @discoveredSids = (keys %$dynamicSids); my $dbDetails = getDBDetailsDiscovery($result,$port,$portInfo->{HOST},@discoveredSids); my $sid ; EMD_PERL_DEBUG("$LOG_CATEGORY dynamically discovered sids for address \"$address\""); foreach $sid (keys %$dbDetails) { EMD_PERL_DEBUG("$LOG_CATEGORY dynamic sid =\"$sid\""); if(! defined $dynamicSids->{$sid} || equalHosts($portInfo->{HOST}, $LOCAL_HOST_VIP_NAME)) { $dynamicSids->{$sid} = $dbDetails->{$sid}; } } } #Get lsnrctl output for a command sub getLsnrctlOutput { my ($oracleHome,$passwordList,@cmds) = @_; my $executable; $executable = getListenerControl($oracleHome); my $result = "" ; if(-e $executable) { my @commands ; my $totalPswd = @$passwordList; my $currPswdInex = 0; do { @commands = (); my $pswd; #Add password if present if($currPswdInex < $totalPswd) { push(@commands,"set password ".$passwordList->[$currPswdInex++]); } foreach my $cmdLine (@cmds) { push(@commands,$cmdLine); } eval { $result = getRunCommandOutput($oracleHome,$executable,@commands); }; #if there is a password error try the next password, if there is #password error #TNS-01169: The listener has not recognized the password }while($result =~ /TNS-01169/i && $currPswdInex < $totalPswd); } return $result; } #Gets the Oracle Home of the listener #from log or trace directory. #If the listener is not running from the passed tnsAdminDir, associate the #passed Oracle Home to the listener. #By default, associate the passed Oracle Home to the listener. sub getListenerHome { my ($ohomesRef,$name,$oHome,$tnsAdminDir,@passwords) = @_; EMD_PERL_DEBUG("$LOG_CATEGORY In getListenerHome for $name,$oHome,$tnsAdminDir"); my @commands = (); push(@commands,"set current_listener $name"); push(@commands,"status"); push(@commands,"show log_directory"); push(@commands,"show trc_directory"); push(@commands,"exit"); #Set the TNS_ADMIN to the passed tnsAdminDir, backup the old one my $oldTNS_ADMIN = $ENV{TNS_ADMIN}; $ENV{TNS_ADMIN} = $tnsAdminDir; my $result = getLsnrctlOutput($oHome,\@passwords,@commands); #Restore the old TNS_ADMIN if(defined $oldTNS_ADMIN) { $ENV{TNS_ADMIN} = $oldTNS_ADMIN; } else { delete ($ENV{TNS_ADMIN}); } #If there are no TNS errors and listener is running #using the passed tnsAdminDir, check the log and trace directory for OH if ($result !~ /^.*TNS-[0-9]*/i && isThisListenerRunning($result,$tnsAdminDir,$name)) { EMD_PERL_DEBUG("$LOG_CATEGORY $name is running from $tnsAdminDir"); my @resultArray = split /\n/, $result; foreach my $ln (@resultArray) { if ( $ln !~ /log_directory/i && $ln !~ /trc_directory/i) { next; } if($ln =~ /^(.*)\"log_directory\"\s+\w+\s+\w+\s+(.*)/i) { my $lsnrHome ; return $lsnrHome if (defined ($lsnrHome= getHomeFromDir($ohomesRef,"log",$2,$oHome))); } if($ln =~ /^(.*)\"trc_directory\"\s+\w+\s+\w+\s+(.*)/i) { my $lsnrHome ; return $lsnrHome if (defined ($lsnrHome= getHomeFromDir($ohomesRef,"trace",$2,$oHome))); } } } else { EMD_PERL_DEBUG("$LOG_CATEGORY $name is NOT running from $tnsAdminDir"); } return $oHome; } #Checks the log/trace directory for Oracle Home of the listener #If the log directory matches OH/network/log for any valid OH, then that's #the Oracle Home of the listener. #If the trace directory matches OH/network/trace for any valid OH, then that's #the Oracle Home of the listener. #Otherwise, return undefined home. sub getHomeFromDir { my ($ohomesRef,$dirName,$dir,$oHome) = @_; my $foundHome; my $endingSlash = "/" if ($dir =~ /\/$/ || $dir =~ /\\$/); EMD_PERL_DEBUG("$dirName directory = [$dir] compare against [$oHome/network/$dirName$endingSlash]"); #Sometimes there is an ending slash in the directory #need to add that to the comparing directory. #Otherwise, comparison fails on Windows if(isSameFileSystemEntity( $dir,"$oHome/network/$dirName$endingSlash")) { $foundHome = $oHome; EMD_PERL_DEBUG("$LOG_CATEGORY Passed home is the home"); } else { foreach my $home (@$ohomesRef) { if($home ne $oHome && isSameFileSystemEntity( $dir,"$home/network/$dirName$endingSlash")) { $foundHome = $home; EMD_PERL_DEBUG("$LOG_CATEGORY Non-Passed home is the home"); last; } } } return $foundHome; } #Update $portTable with port, protocol,ohome, passwords to discover dynamic sids #with port as the key sub updateListenerData { my ($oracleHome,$portTable,$addresses,@passwords) = @_; my ($port,$protocol,$host) = ("","",""); foreach my $addr (@$addresses) { $port = $addr->{PORT} if defined($addr->{PORT}); $protocol = $addr->{PROTOCOL} if defined($addr->{PROTOCOL}); $host = $addr->{HOST} if defined($addr->{HOST}); EMD_PERL_DEBUG("$LOG_CATEGORY Address = $host,$port,$protocol"); if( defined $port && $port ne "" && defined $protocol && $protocol ne "" ) { my $portInfo = $portTable->{$port}; if(defined $portInfo) { #info already present, need to update info #password only #update passwords my $passwordList = $portInfo->{PASSWORDS}; my $pswd; foreach $pswd (@passwords) { push(@$passwordList,$pswd); } } else { $portInfo->{ORACLE_HOME} = $oracleHome; $portInfo->{PROTOCOL} = $protocol; $portInfo->{HOST} = $host; my @passwordList = (); foreach my $pswd (@passwords) { push(@passwordList,$pswd); } $portInfo->{PASSWORDS} = \@passwordList; $portTable->{$port} = $portInfo; } } } } ##print listener target entry sub printListenerEntry { my ($targetName,$oraDir,$name,$lsnrHost,$hostName,$oHome,$port) = @_; $lsnrHost = resolveLsnrHostName($lsnrHost,$hostName); print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; print "\n"; EMD_PERL_INFO("$LOG_CATEGORY listener target \"${targetName}_$hostName\" discovered. Details: [$oraDir,$name,$lsnrHost,$hostName,$oHome,$port]"); } #Gets a unique Database target name sub getDatabaseTargetName { my ($targetName,$sid,$hostName,$dbTargetNames) = @_; my $useSidHostName = 0; if(trim($targetName) eq "") { $targetName = "${sid}_$hostName"; $useSidHostName = 1; } my $counter = 0; my $retTargetName = $targetName; my $uniqueNotFound = 1; my $dbTargetName; while($uniqueNotFound) { $uniqueNotFound = 0; if(contains($retTargetName,@$dbTargetNames)) { if($useSidHostName) { $retTargetName = $sid."_".$counter."_".$hostName; } else { $retTargetName = $targetName . $counter; } $counter++; $uniqueNotFound = 1; } } push(@$dbTargetNames,$retTargetName); return $retTargetName; } ##print Oracle Database target entry # if encounters '+' in SID, print to osm targets instead sub printOracleDatabaseEntry { my ($targetName,$sid,$lsnrHost,$hostName,$oHome,$port,$servName,$dbTargetNames) = @_; $lsnrHost = resolveLsnrHostName($lsnrHost,$hostName); $targetName = getDatabaseTargetName($targetName,$sid,$hostName,$dbTargetNames); # if discovered SID is preceded with '+', it belongs to osm target list if ( $sid =~ /^\+/ ) { printOracleStorageManagerEntry( $targetName, $sid, $hostName, $oHome, $port, $servName ); return; } print "\n"; print "\n"; print "\n"; if(isPasswordValid("dbsnmp","dbsnmp",$oHome, $sid)) { print "\n"; } print "\n"; print "\n"; print " \n"; print " \n"; # print " \n"; print "\n"; EMD_PERL_INFO("$LOG_CATEGORY database target \"$targetName\" discovered. Details: [$targetName,$sid,$lsnrHost,$hostName,$oHome,$port,$servName]"); } # print Oracle Storage Manager target entries # service name and emd perl trace currently not in use sub printOracleStorageManagerEntry { my ($targetName,$sid,$hostName,$oHome,$port,$servName) = @_; # target name already processed print "\n", "\n", "\n", "\n", "\n", "\n", " \n", # " \n", # " \n", "\n"; EMD_PERL_INFO("$LOG_CATEGORY osm_instance target \"$targetName\" discovered. Details: [$targetName,$sid,$hostName,$oHome,$port,$servName]"); } #Get the initialization file for the sid given SID and Ohome sub getInitFile { my ($SID,$OracleHome) = @_; my $initDir = getDefaultInitFileLocation($OracleHome); my $retInitFile; if(-e ($initDir . "/spfile$SID.ora")) { $retInitFile = ($initDir . "/spfile$SID.ora"); } elsif (-e ($initDir . "/spfile.ora")) { $retInitFile = ($initDir . "/spfile.ora"); } elsif (-e ($initDir . "/init$SID.ora")) { $retInitFile = ($initDir . "/init$SID.ora"); } return $retInitFile; } #Get the local listener address for the sid given SID and Ohome #Return a reference for an array of addresses # ( # { # PROTOCOL = "TCP", # HOST = "machine", # PORT = "1234", # }, # { # PROTOCOL = "TCP", # HOST = "machine", # PORT = "1222", # } # ) # sub getLocalListenerAddresses { my ($SID,$OracleHome) = @_; my $initFile = getInitFile($SID,$OracleHome); #The default listener my @defaultAddresses = ( { PROTOCOL => "TCP", HOST => $hostName, PORT => "1521", } ); my $retAddresses = \@defaultAddresses; my @addresses; if (defined $initFile && (-e $initFile)) { my ($localListenerValue ) = discoverParameterValue($OracleHome, $SID, "LOCAL_LISTENER", $SID); if(defined $localListenerValue) { my $addresses = getAddresses($localListenerValue); if(@$addresses == 0) { my @namedAddresses = getCharsSeparatedWords($localListenerValue,","); #resolve named address to an address or address list from the #tnsnames.ora my $addresses = getAddressesFromNames($OracleHome,@namedAddresses,); if(defined $addresses && @$addresses != 0) { $retAddresses = $addresses; } } else { $retAddresses = $addresses; } } } return $retAddresses; } sub getAddressesFromNames { my ($OracleHome,@namedAddresses) = @_; # Check if ORATAB env is specified my $tnsnamesFile ; my $addresses; if ( defined $ENV{TNS_ADMIN} ) { my $tnsAdminDir = trim ( $ENV{TNS_ADMIN} ); if (! -d $tnsAdminDir ) { $tnsAdminDir = ""; } if($tnsAdminDir ne "") { $addresses = resolveAddressesFromNames($tnsAdminDir,\@namedAddresses) } } if(! (defined $addresses)) { $addresses = resolveAddressesFromNames(getDefaultTNSAdmin($OracleHome),\@namedAddresses) ; } return $addresses; } sub resolveAddressesFromNames { my ($tnsAdminDir,$namedAddresses) = @_; my $addresses; my $tnsnamesFile; my $tnsnamesInfoRef ; my $sqlnetFile ; my $sqlnetInfo ; my $addrValue; my $defaultDomain = ""; #print "TNSADMIN = [$tnsAdminDir]\n"; if ( -d $tnsAdminDir ) { $tnsnamesFile = $tnsAdminDir ."/tnsnames.ora"; #print "tnsnames.ora file = [$tnsnamesFile]\n"; if(-e $tnsnamesFile ) { $sqlnetFile = $tnsAdminDir ."/sqlnet.ora"; $sqlnetInfo = parseOracleConfigFile($sqlnetFile); if(defined $sqlnetInfo) { $defaultDomain = trim($sqlnetInfo->{"NAMES.DEFAULT_DOMAIN"}); #print "setting default domain = [$defaultDomain]\n"; } } $tnsnamesInfoRef = parseOracleConfigFile($tnsnamesFile); if(defined $tnsnamesInfoRef) { foreach my $namedAddr (@$namedAddresses) { if($namedAddr !~ /\./) { #Does not contain domain, add domain if($defaultDomain ne "") { $namedAddr .=".".$defaultDomain; #print "Domain added [$defaultDomain]\n"; } } #print "Check named address [$namedAddr]\n"; $addrValue = $tnsnamesInfoRef->{uc ($namedAddr)}; # #print "Value = [$addrValue]\n"; if(defined $addrValue) { $addresses = getAddresses($addrValue); }#End of if(defined $addrValue) }# End of foreach $namedAddr (@$namedAddresses) }# End of if(defined $tnsnamesInfo) }# End of if ( -d $tnsAdminDir ) return $addresses; } # Return: an array of words separated by zero or more given chars sub getCharsSeparatedWords { my ($paramValue,$charList) = @_; my $wd; my @words; #print "paramValue =[$paramValue], charList =[$charList] \n"; while ($paramValue =~ /(\s*\w+\s*)[$charList]*/g) { $wd = $1; #print "wd =[$wd]\n"; $wd =~ s/^\s*|\s*$//; push @words, $wd if ($wd ne ""); } return @words; } #strips leading and trailing spaces and returns the string sub trim { my $origStr = $_[0]; #Strip trailing and leading $origStr =~ s/^\s*|\s*$//g; return $origStr; } ############################################################################## ## Start of RAC Discovery Functions # ############################################################################## # Usage: printRACDatabaseEntries($racInstsRefs, \%racDBHome, # \%racDBLsnrHost, \%racDBPort, \%racDBSID, $hostName, \%racDBServiceName, \%racDBGlbName, $clusterRef); # $racInstsRefs is the one returned by discoverRacTargets() # $hostName is the second command line argument # %racDBHome, %racDBPort, %racDBSID, %racDBServiceName, %cluster are as defined # in printDatabaseAndListnerTargets sub printRACDatabaseEntries { my ($racInstsRefs, $racDBHome, $racDBLsnrHost, $racDBPort, $racDBSID, $hostName, $servName, $racDBGlbName, $cluster) = @_; # good rac databases foreach my $racDB (keys %$racInstsRefs) { if (defined $racDBSID->{$racDB}) { my $assocTargetName = &getInstName($racDBGlbName->{$racDB}, $racDBSID->{$racDB}); my $racTarget = $racDBGlbName->{$racDB}; $racTarget = $racTarget . $hintParams{"db_target_suffix"} if defined $hintParams{"db_target_suffix"}; $racTarget = $hintParams{"db_target_prefix"}. $racTarget if defined $hintParams{"db_target_prefix"}; print <<__END; __END EMD_PERL_INFO("$LOG_CATEGORY rac_database target \"$racTarget\" discovered. Details: [$racTarget,$assocTargetName ( $racDBSID->{$racDB} ),$servName->{$racDB},$cluster->{NAME}]"); } else { EMD_PERL_DEBUG("$LOG_CATEGORY SKIPPED Rac database '$racDB': no valid sid found on the host"); } } } # Usage: printDiscoveryErrors($errRefs, $hostName) # $errRefs is the one returned by discoverRacTargets() and further filled by discoveryServiceName() sub printDiscoveryErrors { my ($errRefs, $hostName) = @_; foreach my $err (keys %$errRefs) { my $escapedErrMsg = escapeXMLChar($errRefs->{$err}); $escapedErrMsg = convertToUTF8($escapedErrMsg); print <<__END; $escapedErrMsg __END } # # # # } ##print Oracle Database target entry sub printRACInstanceEntry { my ($sid,$lsnrHost, $hostName,$oHome,$port,$racDBName, $servName) = @_; $lsnrHost = resolveLsnrHostName($lsnrHost,$hostName); my $instName = &getInstName($racDBName, $sid); my $dbsmpPasswd ="dbsnmp"; $racDBName = $racDBName . $hintParams{"db_target_suffix"} if defined $hintParams{"db_target_suffix"}; $racDBName = $hintParams{"db_target_prefix"}. $racDBName if defined $hintParams{"db_target_prefix"}; print "\n"; print "\n"; print "\n"; if(isPasswordValid("dbsnmp",$dbsmpPasswd,$oHome, $sid)) { print "\n"; } print "\n"; print "\n"; my $osid = (defined $RacSidConversionMap{$sid})? $RacSidConversionMap{$sid} : $sid; print " \n"; print " \n"; print " \n"; print " \n"; print " \n"; print "\n"; } # Usage: ($clusterRef, $racInstsRefs, $errRefs) = discoverRacTargets($ohomesRef, $hostName); # $ohomesRef is the reference of an array of Oracle Homes # return reference of three hashtables. See findRacTargetsFromOracleHome() for # more details # sub discoverRacTargets { my (@oracleHomes) = @{$_[0]}; my $hostName = $_[1]; addToArrayIfNotExisting(\@oracleHomes, $ENV{ORACLE_HOME}) if (defined $ENV{ORACLE_HOME}); my ($clusterRef, $racInstsRefs, $errRefs); my $oracleHome; my ($racOracleHome, $srvctlVersion) = ("", "0.0.0.0.0"); my %errs; my ($clusterName, $crsOh) = ("",""); my $warn_cluster_found = 0; # discover clusterName and crsOh ($clusterName, $crsOh) = getClusterName($emdRoot, $crsHome); if (defined $ENV{CLUSTER_NAME}) { # UI can mandidate a clusterwide discovery $clusterName = $ENV{CLUSTER_NAME}; EMD_PERL_DEBUG("$LOG_CATEGORY ENV{CLUSTER_NAME}=$clusterName"); } # if the UI wants to be warned when cluster is found, do so if ($clusterName ne "" && defined $ENV{OMSENV_WARN_CLUSTER_FOUND}) { $warn_cluster_found = 1; } if ($clusterName eq "") { # if clusterName is empty, then we are not in a cluster. Stop here EMD_PERL_DEBUG("$LOG_CATEGORY discoverRacTargets: not in a cluster"); return ((), (), ()); } # remember it's in a cluster $CLUSTER_NAME = $clusterName; $CRS_HOME = $crsOh if (defined($crsOh)); EMD_PERL_DEBUG("discoverRacTargets: cluster is '$clusterName'"); # get newest srvctl foreach $oracleHome (@oracleHomes) { EMD_PERL_DEBUG("$LOG_CATEGORY discoverRacTargets: looking in $oracleHome..."); if (-e "$oracleHome/bin/srvctl" || -e "$oracleHome/bin/srvctl.bat") { my ($err, $version) = getSrvCtlVersion($oracleHome); if ($err eq "") { EMD_PERL_DEBUG("$LOG_CATEGORY discoverRacTargets: srvctl found, version $version"); $err = srvctl_sanity_check($oracleHome, $version); if ($err eq "") { if (compareVersions($version, $srvctlVersion) == 1) { $srvctlVersion = $version; $racOracleHome = $oracleHome; } } else { $errs{$oracleHome} = $err; } } else { $errs{$oracleHome} = $err; } } } if ($racOracleHome ne "") { ($clusterRef, $racInstsRefs, $errRefs) = findRacTargetsFromOracleHome($racOracleHome, $hostName, $srvctlVersion); } $clusterRef->{NAME} = $clusterName; # we need to put the errors returned by getSrvCtlVersion() in the $errRefs foreach my $k (keys %errs) { $errRefs->{$k} = $errs{$k}; } if ($warn_cluster_found) { $errRefs->{"WARN_CLUSTER_FOUND"} = $clusterName; } ($clusterRef, $racInstsRefs, $errRefs); } # Usage: ($clusterRef, $racInstsRefs, $errRefs) = # findRacTargetsFromOracleHome($oracleHome, $hostName, $srvctlVersion) # $srvctlVersion is optional. If not specified, the program will try to find out # # Logic: # if ("$oracleHome/bin/lsnodes" exists) # { # 1. run "$OracleHome/bin/lsnodes" to get the cluster nodes # 2. run "$OracleHome/bin/srvctl config" to get all rac databases in the cluster # 3. foreach $racDatabase discovered in 2 # { # run "$OracleHome/bin/srvctl config database -d $racDatabase" (for version >= 9.2) # or "$OracleHome/bin/srvctl config database -p $racDatabase -n $hostName" (9.0.1) # to get the ($racInstanceName, $racInstanceOracleHome) on the host being discovered. # } # } # # return references of three hashtables ($clusterRef, $racInstsRefs, $errRefs), in the following format # # $clusterRef = { # #NAME => "cluster1", # #NODES => [ "sun1.example.com", "sun2.example.com", "sun3.example.com" ], # RACDATABASES => [ "racDB1", "racDB2", "racDB3", "racDB4" ] # } # # For now, $racInstsRefs only contains rac instances on $hostName. But the data structure is extensible # for instances not on the $hostName # $racInstsRefs = { # # "racDB1" => [ # [ "sun1.example.com", "racDB11", "/oracle/9.2.0" ], # #[ "sun2.example.com", "racDB12", "/oracle/9.2.0" ] # ], # # # "racDB3" => [ # [ "sun1.example.com", "racDB31", "/oracle/9.3.0" ], # #[ "sun2.example.com", "racDB32", "/oracle/9.3.0" ], # #[ "sun3.example.com", "racDB32", "/oracle/9.3.0" ] # ] # } # # $errRefs = { # "racDB3" => "cannot execute "srvctl ...", # "racDB4" => "PRKR-1007 : ...", # "/oracle/home" => "bad '/oracle/home/bin/srvctl config database'..", # } # # # sub findRacTargetsFromOracleHome { my ($oracleHome, $hostName, $srvctlVersion) = @_; my ($clusterRef, $racInstsRefs, $errRefs) = ((), (), ()); my ($cmd, $err, $output); # bug 3469118 workaround my $orgDIR = changeCWDForSrvctlIfNecessary($oracleHome, $srvctlVersion); EMD_PERL_DEBUG("$LOG_CATEGORY findRacTargetsFromOracleHome: discovering RAC targets in $oracleHome"); if (compareVersions($srvctlVersion, "10.0.0.0.0") >= 0) { #Get the VIP of the machine $LOCAL_HOST_VIP_NAME = getVIPName($oracleHome, $hostName); EMD_PERL_DEBUG("VIP Name on $hostName is $LOCAL_HOST_VIP_NAME"); } #get the rac databases in the cluster if (-e "$oracleHome/bin/srvctl" || -e "$oracleHome/bin/srvctl.bat") { $cmd = "$oracleHome/bin/srvctl config"; EMD_PERL_DEBUG("$LOG_CATEGORY findRacTargetsFromOracleHome: executing 'srvctl config'"); my $lib_path = unset_lib_path_env(); ($err, $output) = executeCommand($cmd, $oracleHome); set_lib_path_env($lib_path); if ($err ne "") { $errRefs->{$oracleHome} = $err; } else { #rac database found EMD_PERL_DEBUG("$LOG_CATEGORY findRacTargetsFromOracleHome: 'srvctl config' return $output"); my @racDBList = split /\n/, $output; $clusterRef->{RACDATABASES} = \@racDBList; if ($srvctlVersion eq "") { ($err, $srvctlVersion) = getSrvCtlVersion($oracleHome); if ($err ne "") { $errRefs->{$oracleHome} = $err; } } if ($srvctlVersion ne "") { my $before92 = (compareVersions($srvctlVersion, "9.2.0.0.0") == -1); foreach my $racDB (@racDBList) { if ($before92) { # 9.0.1 database $cmd = "$oracleHome/bin/srvctl config database -p $racDB -n $hostName" } else { $cmd = "$oracleHome/bin/srvctl config database -d $racDB"; } EMD_PERL_DEBUG("$LOG_CATEGORY findRacTargetsFromOracleHome: executing $cmd"); my $lib_path = unset_lib_path_env(); ($err, $output) = executeCommand($cmd, $oracleHome); set_lib_path_env($lib_path); # on NT, CAPITAL case is used for simplicity $racDB = convertSIDForOS($racDB); if ($err ne "") { $errRefs->{$racDB} = $err; } else { EMD_PERL_DEBUG("$LOG_CATEGORY findRacTargetsFromOracleHome: returned $output"); my @instRefAry = (); my @instInfs = split /\n/, $output; foreach my $instInf (@instInfs) { if ($instInf =~ /^([^\s]+)\s([^\s]+)\s(.+)$/) { if (&equalHosts($1, $hostName)) { # on NT, CAPITAL case is used for simplicity my $racsid = convertSIDForOS($2); # 3667625 workaround for rac sid mismatch problem $RacSidConversionMap{$racsid} = $2; push @instRefAry, [$1, $racsid, $3]; EMD_PERL_DEBUG("$LOG_CATEGORY findRacTargetsFromOracleHome: Instance [$1, $2, $3] is on the host"); # Bug 3468650 - contine to find all other instances on the host # last; } } else { $errRefs->{$racDB} = "Unknown format from output of " . "\"$cmd\": " . $output; EMD_PERL_ERROR("findRacTargetsFromOracleHome: $errRefs->{$racDB}"); last; } } if (!defined $errRefs->{$racDB} && @instRefAry) { $racInstsRefs->{$racDB} = \@instRefAry; } } } } } } else { $errRefs->{$oracleHome} = "$oracleHome/bin/srvctl doesn't exist"; EMD_PERL_ERROR("findRacTargetsFromOracleHome: $errRefs->{$oracleHome}"); } # bug 3469118 workaround: we'll revert the cwd if($orgDIR ne "__CURRENT_DIR_UNCHANGED__") { chdir($orgDIR); } ($clusterRef, $racInstsRefs, $errRefs); } # getSrvCtlVersion($OracleHome) # return ($err, $version) # when $err is empty, the $version contains the version $OracleHome/bin/srvctl sub getSrvCtlVersion { my $oracleHome = $_[0]; my ($err, $output, $version); if (-e "$oracleHome/bin/srvctl" || -e "$oracleHome/bin/srvctl.bat") { my $lib_path = unset_lib_path_env(); ($err, $output) = executeCommand("$oracleHome/bin/srvctl -V", $oracleHome); set_lib_path_env($lib_path); if ($err eq "") { if ($output =~ /\d+\.\d+\.\d+\.\d+/) { $version = $&; } else { $err = "Wrong version format: $output"; EMD_PERL_ERROR("getSrvCtlVersion: $err"); } } } else { $err = "$oracleHome/bin/srvctl doesn't exist"; EMD_PERL_ERROR("getSrvCtlVersion: $err"); } ($err, $version); } # Usage: ($err, $output) = executeCommand($cmd, $envOracleHome, $envJavaHome) # # Run the $cmd and # if success, return the empty to $err and output string to $output # else, return the error msg to $err and empty to $output sub executeCommand { my ($cmd, $envOracleHome, $envJavaHome) = @_; my ($oldOH, $oldJH); $oldOH = $ENV{ORACLE_HOME}; if ($envOracleHome ne "") { $ENV{ORACLE_HOME} = $envOracleHome; } else { delete $ENV{ORACLE_HOME}; } $oldJH = $ENV{JAVA_HOME}; if ($envJavaHome ne "") { $ENV{JAVA_HOME} = $envJavaHome; } else { delete $ENV{JAVA_HOME}; } my $err = ""; my $output = ""; if (open(CMDOUTPUT, "$cmd 2>&1 |")) { my @outputs = ; $output = join "", @outputs; if (!close(CMDOUTPUT)) { # close error if ($output ne "") { $err = "\"${cmd}\" returned: \"" . $output . "\""; $output = ""; } else { $err = "bad \"$cmd\": $! $?"; } } } else { # open error $err = "cannot execute \"$cmd\": $!"; } if ($oldOH eq "") { delete $ENV{ORACLE_HOME}; } else { $ENV{ORACLE_HOME} = $oldOH; } if ($oldJH eq "") { delete $ENV{JAVA_HOME}; } else { $ENV{JAVA_HOME} = $oldJH; } EMD_PERL_ERROR("executeCommand: $cmd: $err") if ($err ne ""); ($err, $output); } sub escapeXMLChar { my $newStr = $_[0]; $newStr =~ s/&/&/g; $newStr =~ s//>/g; $newStr =~ s/\"/"/g; $newStr =~ s/'/'/g; $newStr; } # compareVersions($v1, $v2) # return 1 if $v1 > $v2 # 0 if $v1 = $v2 # -1 if $v1 < $v2 sub compareVersions { my ($v1, $v2) = @_; my @subv1; my @subv2; while ($v1 =~ /\d+/g) { push @subv1, $&; } while ($v2 =~ /\d+/g) { push @subv2, $&; } my $size = (@subv1 > @subv2)? @subv1 : @subv2; my $i; for($i=0; $i<$size; $i++) { if ($subv1[$i] > $subv2[$i]) { return 1; } if ($subv1[$i] < $subv2[$i]) { return -1; } } return 0; } # addToArrayIfNotExisting ($aryRef, $string) # if there is no element, $s, in @$aryRef such that ($s eq $string), then # push @$aryRef, $string sub addToArrayIfNotExisting { my ($aryRef, $string) = @_; foreach my $s (@$aryRef) { if ($s eq $string) { return 0; } } push @$aryRef, $string; 1; } # Usage: ($err, $targetName) = getTargetName($oracleHome, $sid, $isRac) # return the database target name if found. If any error occured, it'll be returned in $err # # Logic: # find value of db_unique_name # if not found and db_domain exists return db_name.db_domain # else return db_name # sub getTargetName { my ($oracleHome, $sid, $isRac) = @_; my $err = ""; my $isStandby = 0; #get param with quotes preserved my ($dbUniqueName) = discoverParameterValue($oracleHome, $sid, "db_unique_name", $sid,1); if ($dbUniqueName eq "" || $dbUniqueName eq "''" || $dbUniqueName eq '""') { # bug fix 2755537 #$err = checkErrorMessageInParameterDiscovery(); # # if ($err ne "") # { # # error # $err = "Failed to retrieve value for parameter \"$sid.db_unique_name\": " . $err; # # return ($err, ""); # } # #Check if the database is a standby if (isStandby($oracleHome, $sid)) { EMD_PERL_INFO("$LOG_CATEGORY $sid is a standby db"); #the target name would be sid_hostname $isStandby = 1; if (!$isRac) { $dbUniqueName = "${sid}_$hostName"; } } if (!$isStandby || $isRac) { # db_unique_name not specified, try db_name.db_domain #get param with quotes preserved my ($dbName) = discoverParameterValue($oracleHome, $sid, "db_name", $sid,1); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error $err = "Failed to retrieve value for parameter \"$sid.db_name\": " . $err; return ($err, ""); } # db_name retrieve succeeded, try db_domain #get param with quotes preserved my ($db_domain) = (""); if(!(defined $hintParams{"no_db_domain"} && "true" eq $hintParams{"no_db_domain"} )) { ($db_domain) = discoverParameterValue($oracleHome, $sid, "db_domain", $sid,1); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error $err = "Failed to retrieve value for parameter \"$sid.db_domain\": " . $err; return ($err, ""); } } $dbName = convertToUcIfNotQuoted($dbName); $dbName = trimQuote($dbName); $db_domain = convertToUcIfNotQuoted($db_domain); $db_domain = trimQuote($db_domain); # db_name and db_domain are retrieved if($db_domain ne "") { $dbUniqueName = $dbName . "." . $db_domain; } else { $dbUniqueName = $dbName; } } } else { # db_name retrieve succeeded, try db_domain #get param with quotes preserved my ($db_domain) = (""); if(!(defined $hintParams{"no_db_domain"} && "true" eq $hintParams{"no_db_domain"} )) { ($db_domain) = discoverParameterValue($oracleHome, $sid, "db_domain", $sid,1); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error $err = "Failed to retrieve value for parameter \"$sid.db_domain\": " . $err; return ($err, ""); } } # db_name and db_domain are retrieved $dbUniqueName = convertToUcIfNotQuoted($dbUniqueName); $dbUniqueName = trimQuote($dbUniqueName); $db_domain = convertToUcIfNotQuoted($db_domain); $db_domain = trimQuote($db_domain); if($db_domain ne "") { $dbUniqueName = $dbUniqueName . "." . $db_domain; } } if ($isRac && $isStandby) { $dbUniqueName .= "_$CLUSTER_NAME"; } ("", $dbUniqueName); } #Check if the database is a standby #The database is standby if one of the following is true: # - ora_mrp<0-9>*_sid process is running # - fal_client is present in the init.ora # - fal_server is present in the init.ora # sub isStandby { my ($oracleHome, $sid) = @_; if((get_osType() ne 'WIN') ) { if ( oraProcExists('mrp[0-9]*', $sid) ) { #MRP standby process process exists #This is standby database EMD_PERL_DEBUG("$LOG_CATEGORY mrp process found for, its a standby db"); return 1; } } my $standbyParam; ($standbyParam) = discoverParameterValue($oracleHome, $sid, "fal_client", $sid,1); my $err; $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error EMD_PERL_DEBUG("$LOG_CATEGORY Failed to retrieve value for parameter \"$sid.fal_client\": "); } if($standbyParam ne "") { return 1; } ($standbyParam) = discoverParameterValue($oracleHome, $sid, "fal_server", $sid,1); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error EMD_PERL_DEBUG("$LOG_CATEGORY Failed to retrieve value for parameter \"$sid.fal_server\": "); } if($standbyParam ne "") { return 1; } return 0; } # Usage: ($err, $serviceName) = discoveryServiceName($oracleHome, $sid) # return the service name if found. If any error occured, it'll be returned in $err # # Logic: # find value of service_names # if not found and db_domain exists return db_name.db_domain # else return db_name # sub discoveryServiceName { my ($oracleHome, $sid) = @_; my $err = ""; EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: discovering value of parameter service_names"); my ($serviceName) = discoverParameterValue($oracleHome, $sid, "service_names", $sid); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { # error $err = "Failed to retrieve value for parameter \"$sid.service_names\": " . $err; return ($err, ""); } EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: service_names = $serviceName"); if ($serviceName eq "") { EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: discovering value of parameter db_unique_name"); ($serviceName) = discoverParameterValue($oracleHome, $sid, "db_unique_name", $sid); EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: db_unique_name = $serviceName"); if ($serviceName eq "") { # service_names not specified, try db_name EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: discovering value of parameter db_name"); ($serviceName) = discoverParameterValue($oracleHome, $sid, "db_name", $sid); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error $err = "Failed to retrieve value for parameter \"$sid.db_name\": " . $err; return ($err, ""); } } EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: db_name = $serviceName"); } my ($db_domain) = (""); if(!(defined $hintParams{"no_db_domain"} && "true" eq $hintParams{"no_db_domain"} )) { # get db_domain EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: discovering value of parameter db_domain"); ($db_domain) = discoverParameterValue($oracleHome, $sid, "db_domain", $sid); $err = checkErrorMessageInParameterDiscovery(); if ($err ne "") { #error $err = "Failed to retrieve value for parameter \"$sid.db_domain\": " . $err; return ($err, ""); } EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: db_domain = $db_domain"); } # put them together if ($db_domain ne "" && $serviceName !~ /$db_domain$/) { $serviceName = $serviceName . "." . $db_domain; } EMD_PERL_DEBUG("$LOG_CATEGORY discoveryServiceName: serviceName = $serviceName"); ("", $serviceName); } # Usage: equalHosts($host1, $host2) # return 1 if the one of $host1's ip addresses equals one of $host2's # otherwise return 0 sub equalHosts { if ($_[0] eq "" || $_[1] eq "") { return 0; } my ($name1, $aliases1, $addrtype1, $length1, @addrs1) = gethostbyname($_[0]); my ($name2, $aliases2, $addrtype2, $length2, @addrs2) = gethostbyname($_[1]); foreach my $a1 (@addrs1) { foreach my $a2 (@addrs2) { return 1 if ($a1 eq $a2); } } 0; } # Usage: filterOutNotSupportedOracleHomes($ohomesRef,$sidsRef) # ($ohomesRef,$sidsRef) are those returned by getOracleHomesAndSids(); # The method will delete the entries with not supported oracle home. sub filterOutNotSupportedOracleHomes { my ($ohomesRef, $sidsRef) = @_; my $sid; for $sid (keys %$sidsRef) { if (!isSupportedHome($sidsRef->{$sid})) { EMD_PERL("$LOG_CATEGORY Oracle Home $sidsRef->{$sid} for sid=$sid is not supported. It is excluded from discovery."); delete $sidsRef->{$sid}; } } my $i; my @ohs = @{$ohomesRef}; splice @$ohomesRef, 0; for($i=0; $i<@ohs; $i++) { if (isSupportedHome($ohs[$i])) { push @{$ohomesRef}, $ohs[$i]; } else { EMD_PERL_INFO("$LOG_CATEGORY Oracle Home $ohs[$i] is not supported. It is excluded from discovery."); } } } # Usage: filterOutBadOracleHomes($ohomesRef,$sidsRef) # ($ohomesRef,$sidsRef) are those returned by getOracleHomesAndSids(); # The method will delete the entries with an oracle home that doesn't exist sub filterOutBadOracleHomes { my ($ohomesRef, $sidsRef) = @_; my $sid; for $sid (keys %$sidsRef) { if (! -e $sidsRef->{$sid}) { delete $sidsRef->{$sid}; } } my $i; my @ohs = @{$ohomesRef}; splice @$ohomesRef, 0; for($i=0; $i<@ohs; $i++) { if (-e $ohs[$i]) { push @{$ohomesRef}, $ohs[$i]; } } } # Usage: removeElementFromArray($arrayRef, $element) # if (existing $e in @$arrayRef such that $e eq $element) # remove it from the array sub removeElementFromArray { my ($arrayRef, $element) = @_; my $i; for($i=0; $i<@$arrayRef; $i++) { if ($arrayRef->[$i] eq $element) { last; } } if ($i < @$arrayRef) { splice @$arrayRef, $i, 1; } } #Usage: getRacDBGlbName($targetName, $dbName) sub getRacDBGlbName { my $targetName = $_[0]; if ($targetName eq "") { $targetName = $_[1]; } $targetName; } #Usage: getInstName($racDBName, $sid) sub getInstName { my $nameinst = $_[0] . "_" . $_[1]; $nameinst = $nameinst . $hintParams{"db_target_suffix"} if defined $hintParams{"db_target_suffix"}; $nameinst = $hintParams{"db_target_prefix"}. $nameinst if defined $hintParams{"db_target_prefix"}; return $nameinst; } #Check if Oracle Home is supported like pre 8.1 sub isSupportedHome { my ($home) = @_; # if (! -e ($home . "/javavm")) # { # return 1; # } # return 0; #return all the homes supported till we get a good logic to filter out #an Old Oracle home return 1; } # Usage: getRidOfRemoteAddresses($addresses, $localHost) # $addresses is the one returned by getListenerAddresses() # # Remove from $addresses any entry whose ip address doesn't match that of $localHost # sub getRidOfRemoteAddresses { my ($addresses, $localHost) = @_; my @addrList = @{$addresses}; splice @$addresses, 0; for(my $i=0; $i<@addrList; $i++) { my $host = ""; $host = $addrList[$i]->{HOST} if (defined($addrList[$i]->{HOST})); if($host ne "" && !&equalHosts($host, $localHost) && !&equalHosts($host, $LOCAL_HOST_VIP_NAME) ) { next; } push @{$addresses}, $addrList[$i]; } } # # The agent's lib_path doesn't work with 92 srvctl even after calling set_lib_path() # Unsetting the lib_path works fine with srvctl # # Return the old lib_path before unset # # This method is adapted from set_lib_path_env() in semd_common.pl sub unset_lib_path_env { my ($oh) = @_; my $rst; if ( get_osType() eq "SOL" || get_osType() eq "LNX" || get_osType() eq "OSF1" ) { $rst = $ENV{LD_LIBRARY_PATH}; delete $ENV{LD_LIBRARY_PATH}; } elsif ( get_osType() eq "HP" ) { $rst = $ENV{SHLIB_PATH}; delete $ENV{SHLIB_PATH}; } elsif ( get_osType() eq "AIX" ) { $rst = $ENV{LIBPATH}; delete $ENV{LIBPATH}; } elsif ( get_osType() eq "MAC OS X" ) { $rst = $ENV{DYLD_LIBRARY_PATH}; delete $ENV{DYLD_LIBRARY_PATH}; } else { # Unsupported Operating System # Do nothing } $rst; } # # Take the lib_path and set it to the env variable # Return the old lib_path # # This method is adapted from set_lib_path_env() in semd_common.pl sub set_lib_path_env { my $libpath = $_[0]; my $rst; if ( get_osType() eq "SOL" || get_osType() eq "LNX" || get_osType() eq "OSF1" ) { $rst = $ENV{LD_LIBRARY_PATH}; $ENV{LD_LIBRARY_PATH} = $libpath; } elsif ( get_osType() eq "HP" ) { $rst = $ENV{SHLIB_PATH}; $ENV{SHLIB_PATH} = $libpath; } elsif ( get_osType() eq "AIX" ) { $rst = $ENV{LIBPATH}; $ENV{LIBPATH} = $libpath; } elsif ( get_osType() eq "MAC OS X" ) { $rst = $ENV{DYLD_LIBRARY_PATH}; $ENV{DYLD_LIBRARY_PATH} = $libpath; } else { # Unsupported Operating System # Do nothing } $rst; } # # Run "$oracleHome/bin/srvctl config", if failed return the error # else return empty # sub srvctl_sanity_check { my ($oracleHome, $srvctlVersion) = @_; # bug 3469118 workaround: my $orgDIR = changeCWDForSrvctlIfNecessary($oracleHome, $srvctlVersion); my $cmd = "$oracleHome/bin/srvctl config"; EMD_PERL_DEBUG("srvctl_sanity_check: $cmd"); my $lib_path = unset_lib_path_env(); my ($err, $output) = executeCommand($cmd, $oracleHome); set_lib_path_env($lib_path); if ($err ne "") { EMD_PERL_DEBUG("srvctl_sanity_check failed: $err"); } EMD_PERL_DEBUG("srvctl_sanity_check passed"); # bug 3469118 workaround: we'll revert the cwd if($orgDIR ne "__CURRENT_DIR_UNCHANGED__") { chdir($orgDIR); } $err; } sub convertToUTF8 { my $value = $_[0]; my $num = 0; my $utf8 = ''; for (my $i = 0; $i < length($value); $i++) { $num = ord(substr($value,$i,1)); if ($num < 0x80) { $utf8 .= chr($num); } else { $utf8 .= chr(0xC0 | (($num >> 6) & 0x03)); $utf8 .= chr(0x80 | ($num & 0x3F)); } } return $utf8; } # Given the output from the services command in raw mode # from the lsnrctl, this subroutine # returns a hashtable for sids found and itss correponding details # For lsnrctl services output in raw mode like: #LSNRCTL> services (ADDRESS=(PROTOCOL=TCP)(HOST=dkapoor-pc3)(PORT=1234)) #Connecting to (ADDRESS=(PROTOCOL=TCP)(HOST=dkapoor-pc3)(PORT=1234)) #Services Summary... #(SERVICE=(SERVICE_NAME=orclServiceName)(INSTANCE=(INSTANCE_NAME=orcloid)(NUM=1)(IN #STANCE_STATUS=UNKNOWN)(HANDLER=(HANDLER_DISPLAY=DEDICATED SERVER)(HANDLER_INFO=L #OCAL SERVER)(HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REFUSED=0)(HANDLE #R_ID=B94B489DEB84-11D6-B6FD-0002A517EED1)(PRE=any)(HANDLER_NAME=DEDICATED)(SESSI #ON=NS)(ADDRESS=(PROTOCOL=beq)(PROGRAM=extproc)(ENVS='ORACLE_HOME=d:\oracle92\test #,ORACLE_SID=orcloid')(ARGV0=extprocPLSExtProc)(ARGS='(LOCAL=NO)')))(NUMREL= #1)))\n" #(SERVICE=(SERVICE_NAME=orcl92.example.com)(INSTANCE=(INSTANCE_NAME=orcl92)(NUM #=1)(INSTANCE_STATUS=UNKNOWN)(HANDLER=(HANDLER_DISPLAY=DEDICATED SERVER)(HANDLER_ #INFO=LOCAL SERVER)(HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REFUSED=0)( #HANDLER_ID=B94B489EEB84-11D6-B6FD-0002A517EED1)(PRE=any)(HANDLER_NAME=DEDICATED) #(SESSION=NS)(ADDRESS=(PROTOCOL=beq)(PROGRAM=oracle)(ENVS='ORACLE_HOME=d:\oracle9 #2\ora92,ORACLE_SID=orcl92')(ARGV0='oracleorcl92')(ARGS='(LOCAL=NO)')))(NUMREL=1))) # # Following hashtable is returned: # ( # orcl92 => # { # SERVICE_NAME => orcl92.example.com, # ORACLE_HOME => d:\oracle92\ora92, # PORT => 1234 (obtained from the first address description) # }, # orcloid => # { # SERVICE_NAME => orclServiceName, # ORACLE_HOME => d:\oracle92\test, # PORT => 1234 # }, # ) # #Assuptions: # 0. The entry for INSTANCE_NAME = *extproc* (ignoring case) is not returned. # 1. If no ORACLE_SID, INSTANCE_NAME or ORACLE_HOME found , the entry is not returned # 2. If the instance is not local to the host, the entry is not returned # sub getDBDetailsDiscovery { my ($result,$port,$lsnrHost,@dynamicDiscoveredSids) = @_; my %dbDetails; if(!defined $port || $port eq "") { return \%dbDetails; } my @resultArray = split /\n/, $result; foreach my $ln (@resultArray) { if($ln !~ /^\s*\(SERVICE/i) { next; } if($ln !~ /(ORACLE_HOME)|(ORACLE_SID)|(INSTANCE_NAME)/i) { next; } my ($srv, @lns) = split /\(INSTANCE=/, $ln; foreach my $line (@lns) { $line = $srv . "(INSTANCE=" . $line; if (!isLocalInstance($line, $lsnrHost)) { EMD_PERL_DEBUG("Ignored: NOT Local instance -- $line"); next; } my ($serviceName, $oracleHome,$oracleSid, $instanceName) = ("","","",""); if($line =~ /\(ENVS='.*ORACLE_SID=(.*?)(,|')/i) { $oracleSid = convertSIDForOS($1); } # is sid not defined get it from INSTANCE_NAME if(!defined $oracleSid || $oracleSid eq "") { if($line =~ /\(INSTANCE_NAME=(.*?)\)/i) { $oracleSid = convertSIDForOS($1); } } if ($oracleSid =~ /extproc/i) { #filter out sids containing with extproc next; } if(contains($oracleSid,@dynamicDiscoveredSids) && !equalHosts($lsnrHost, $LOCAL_HOST_VIP_NAME)) { next; } if($line =~ /\(ENVS='.*ORACLE_HOME=(.*?)(,|')/i) { $oracleHome = $1; } if($line =~ /\(SERVICE_NAME=(.*?)\)/i) { $serviceName = $1; } EMD_PERL_INFO("$LOG_CATEGORY found dynamic sid=\"$oracleSid\" service =$serviceName port = $port host =$lsnrHost home=$oracleHome"); if( defined $oracleSid && $oracleSid ne "") { if(defined $dbDetails{$oracleSid}) { my $sidDetails = $dbDetails{$oracleSid}; my $serviceNamesRef = $sidDetails->{SERVICE_NAME}; push(@$serviceNamesRef,$serviceName); $sidDetails->{SERVICE_NAME} = $serviceNamesRef; } else { my @servNamesArr = $serviceName; my $sidDetails = { ORACLE_HOME=> $oracleHome, SERVICE_NAME => \@servNamesArr, PORT => $port,HOST => $lsnrHost} ; $dbDetails{$oracleSid} = $sidDetails; } } } } return \%dbDetails; } ## ## The following method is written to workaround bug 3469118. ## For pre-10g NT rac, if PATH env doesn't include $oracleHome/bin, ## the srvctl will return error when invoked not within $oracleHome/bin. ## The workaround for this bug is to change the current dir to $oracleHome/bin ## before calling srvctl and set it back when finished ## # Take in $oracleHome and $srvctlVersion # # Return the original current dir if it's changed # Otherwise return "__CURRENT_DIR_UNCHANGED__" sub changeCWDForSrvctlIfNecessary { my ($oracleHome, $srvctlVersion) = @_; my $orgDIR = "__CURRENT_DIR_UNCHANGED__"; if (get_osType() eq 'WIN' && compareVersions($srvctlVersion, "10.0.0.0.0") == -1) { # This is a NT pre-10g srvctl $orgDIR = getcwd; chdir "$oracleHome/bin"; } $orgDIR; } # # isLocalInstance($instanceBlock, $hostname) # Given an instance block from lsnrctl raw service output, something like # # ..(INSTANCE=(INSTANCE_NAME=orcloid)(NUM=1)(INSTANCE_STATUS=UNKNOWN) # (HANDLER=(HANDLER_DISPLAY=DEDICATED SERVER)(HANDLER_INFO=LOCAL SERVER) # (HANDLER_MAXLOAD=0)(HANDLER_LOAD=0)(ESTABLISHED=0)(REF.... # # return 1 if this instance is on the local host (specified by $hostname) as in # the following situations # 1. For dedicated server, one of its HANDLER_INFO equals "LOCAL SERVER" # 2. For shared server, one of its HANDLER_INFO with machine of $hostname # sub isLocalInstance { my ($instance, $hostname) = @_; my $handler_info; while ($instance =~ /HANDLER_INFO=(.*?)\)/ig) { $handler_info = $1; if ($handler_info eq "LOCAL SERVER") { return 1; } if ($handler_info =~ /DISPATCHER\s*{$dbName}) { my @instRefAry = (); push @instRefAry, [$hostName, $sid, $oracleHome]; $racInstsRefs->{$dbName} = \@instRefAry; } else { # already defined. do nothing for now } # we need to the retrieve the sid with original case my ($osid) = discoverParameterValue($oracleHome, $sid, "instance_name", $sid); if ($osid ne "") { $RacSidConversionMap{$sid} = $osid; } return $dbName; } return ""; } # return if the given $sid, $oh is valid or not sub isValidSid { my ($sid, $oHome) = @_; if ( oraProcExists('pmon', $sid) ) { #PMON process exists return 1; } my $initDir = getDefaultInitFileLocation($oHome); if (-e ($initDir . "/lk". uc ($sid))) { #lk file exists return 1; } my $initFile = getInitFile($sid,$oHome); if (defined $initFile && (-e $initFile)) { #initalization file exists return 1; } return 0; } #Gets listener control version. #if not found returns 0. sub getLsnrctlVersion { my ($oracleHome) = @_; my $lsnrctl = getListenerControl($oracleHome); # if version already present, return it return $lsnrctlVersions{$lsnrctl} if (defined $lsnrctlVersions{$lsnrctl}); if(-e $lsnrctl) { my @commands =("version","exit"); my $result = getRunCommandOutput($oracleHome,$lsnrctl,@commands); my @resultArray = split /\n/, $result; foreach my $ln (@resultArray) { if($ln =~ /\s*LSNRCTL (.+) Version ([0-9.a-zA-Z]+?) (.+)/i) { EMD_PERL_INFO("$LOG_CATEGORY The version of the $lsnrctl=[$2]"); $lsnrctlVersions{$lsnrctl} = $2; return $2; } } } EMD_PERL_ERROR("$LOG_CATEGORY Could not get version of $lsnrctl"); $lsnrctlVersions{$lsnrctl} = 0; return 0; } # Test for the presence of an ora_ process sub oraProcExists { my $retval = 0; my ($proc, $sid) = @_; if ( !defined($proc) || !defined($sid) ) { return($retval); } my $uname; chomp($uname=`/bin/uname`) || chomp($uname=`/usr/bin/uname`); my $regexp = "[o]ra_".$proc."_".$sid."\$" ; my $ps_opts = "-ef"; if ( $uname eq "Darwin" ) { # MAC OS $ps_opts = "-x"; } system("/bin/ps $ps_opts | /bin/grep $regexp > /dev/null"); if ($? == 0) { $retval = 1; } return( $retval ); } # ------------------------------ End of File ---------------------------------