#!/usr/local/bin/perl
#
# $Header: emdb/sysman/admin/discover/eventBasedDiscovery.pl /st_emdbsa_11.2/7 2011/07/21 19:51:26 shasingh Exp $
#
# eventBasedDiscovery.pl
#
# Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. 
#
#    NAME
#      eventBasedDiscovery.pl - <one-line expansion of the name>
#
#    DESCRIPTION
#      <short description of component this file declares/defines>
#
#    NOTES
#      <other useful comments, qualifications, etc.>
#
#    MODIFIED   (MM/DD/YY)
#    shasingh    12/05/10 - Backport shasingh_bug-10118817_1 from main
#    shasingh    06/19/09 - increase script timeout
#    shasingh    04/30/09 - add time out
#    shasingh    05/14/08 - improved logic
#    shasingh    03/18/08 - improved perf
#    shasingh    11/27/07 - This module take care of event based discovery and
#                           used for finding missing target attributes during
#                           CRS event based target processing
#    shasingh    11/27/07 - Creation
#
#
# Use the srvctl to retrieve the vip name of the machine specified
#

use strict;

my ( $emdRoot, $hostName ) = @ARGV;

require "$emdRoot/sysman/admin/scripts/semd_common.pl";
require "$emdRoot/sysman/admin/discover/utl/oracledbUtl.pl";
my $UNDEFINED    = "undefined";
my $LOG_CATEGORY = "EVENT_BASED_DISCOVERY: ";
my $CRS_HOME     = $ENV{CRS_HOME};
my $TARGET_TYPE  = $ENV{TARGET_TYPE};
my $SCRIPT_TIMEOUT_VAL = 150; # 2.5 minutes

unset_lib_path_env();

my $dieh = $SIG{__DIE__} if $SIG{__DIE__};
$SIG{__DIE__}='';
eval
{
  local $SIG{ALRM} = sub {
  alarm 0;
  my %erra = ();
  $erra{TimeOut}= "Discovery timed out";
  print "<Targets>\n";
  print "</Targets>\n";
  die "discovery time out"; 
 };
  
  alarm  $SCRIPT_TIMEOUT_VAL ; 
 
  print "<Targets>\n"; 
   doDiscovery();
  print "</Targets>\n";
 
  alarm 0;
 };
$SIG{__DIE__} = $dieh  if $dieh;


sub doDiscovery
{
 
 if ( $TARGET_TYPE eq "oracle_listener" ) 
 {
	doListenerDiscovery();
 }
 elsif($TARGET_TYPE eq "oracle_database")
 {
	doRacInstanceDiscovery();
 }elsif($TARGET_TYPE eq "osm_instance")
 {
    doASMDiscovery();
 }
 
}

sub doRacInstanceDiscovery {
	my $machine = getVIPName( $CRS_HOME, $hostName );
	my $sid = $UNDEFINED;
	my $db_name = $ENV{DB_NAME}; 
	my $cmd = "$CRS_HOME/bin/srvctl status database -d $db_name -S 1";
 	my ( $err, $output ) = executeCommand( $cmd, $CRS_HOME );
 	EMD_PERL_DEBUG("$LOG_CATEGORY doRacInstanceDiscovery-> $cmd returned (err=$err, output=$output)");
 	my $node_name = $ENV{NODE_NAME};
 	EMD_PERL_DEBUG("$LOG_CATEGORY doRacInstanceDiscovery-> node name: $node_name ");
 	if($err eq "")
 	{
  	 my @lns = split /\n/, $output;
  	 for my $ln (@lns)
  	 {
   	  if ($ln =~ /dbunique_name\s*=\s*\{\s*$db_name\s*\}.*?inst_name\s*=\s*\{(.*?)\}.*?node_name\s*=\s*\{\s*$node_name\s*\}.*?up\s*=\s*\{\s*true\s*\}/i)
   	  {
		$sid = $1;
		EMD_PERL_DEBUG("$LOG_CATEGORY doRacInstanceDiscovery-> Found SID : $1");
   	  }
  	 }
 	}
    
	print "<Target TYPE=\"oracle_database\" NAME=\"$UNDEFINED\" >\n";
	print "<Property NAME=\"OracleHome\" VALUE=\"$UNDEFINED\" />\n";
	print "<Property NAME=\"UserName\" VALUE=\"dbsnmp\" ENCRYPTED=\"FALSE\"/>\n";
	print "<Property NAME=\"password\" VALUE=\"dbsnmp\" ENCRYPTED=\"FALSE\"/>\n";
	print "<Property NAME=\"MachineName\" VALUE=\"$machine\" />\n";
	print "<Property NAME=\"Port\" VALUE=\"$UNDEFINED\" />\n";
	print "<Property NAME=\"SID\" VALUE=\"$sid\"/> \n";
	print "<CompositeMembership> \n";
	print "<MemberOf TYPE=\"rac_database\" NAME=\"$UNDEFINED\" ASSOCIATION=\"cluster_member\"/>\n";
	print "</CompositeMembership> \n";
	print "</Target>\n";

}

# Do the scan listener discovery given scan listner name
sub doScanListenerDiscovery 
{
       my ($sacnLsnrName) = @_;
       my $nodeName = exists $ENV{NODE_NAME} ? $ENV{NODE_NAME} : $UNDEFINED;
       my $cmd = "$CRS_HOME/bin/srvctl status scan_listener -S 1";
       my ( $err, $output ) = executeCommand( $cmd, $CRS_HOME );
       EMD_PERL_DEBUG("$LOG_CATEGORY doScanListenerDiscovery-> $cmd returned (err=$err, output=$output)");

       if($err eq "")
       {
        my @lns = split /\n/, $output;
        for my $ln (@lns)
        {
         if ($ln =~ /res_name\s*=\s*\{.*?\.$sacnLsnrName\..*?\}\s*up\s*=\s*\{\s*$nodeName\s*\}/i)
         {
          EMD_PERL_DEBUG("$LOG_CATEGORY doScanListenerDiscovery-> scan listener: $sacnLsnrName exist on node $nodeName ");
          my $ListenerOraDir = getDefaultTNSAdmin($CRS_HOME);
          print "<Target TYPE=\"oracle_listener\" NAME=\"$UNDEFINED\" >\n";
          print "<Property NAME=\"ListenerOraDir\" VALUE=\"$ListenerOraDir\" />\n";
          print "<Property NAME=\"LsnrName\" VALUE=\"$sacnLsnrName\" />\n";
          print "<Property NAME=\"Machine\" VALUE=\"$UNDEFINED\" />\n";
          print "<Property NAME=\"OracleHome\" VALUE=\"$CRS_HOME\" />\n";
          print "<Property NAME=\"Port\" VALUE=\"$UNDEFINED\" />\n";
          print "</Target>\n";
         
         last;
       }
     }
    }
}

sub doListenerDiscovery 
{
        my $LsnrName = $ENV{LsnrName};
        my $isScanLsnr = exists $ENV{isScanLsnr} ? $ENV{isScanLsnr} : "false";
        EMD_PERL_DEBUG("$LOG_CATEGORY doListenerDiscovery-> is scan listener? : $isScanLsnr ");
        # do scan listener discovery
        if (uc($ENV{isScanLsnr}) eq "TRUE")
        {
          return doScanListenerDiscovery($LsnrName);	
        }
        
        my $OracleHome = exists $ENV{OracleHome} ? $ENV{OracleHome} : $UNDEFINED;
        my $Port = exists $ENV{Port} ? $ENV{Port} : $UNDEFINED;
        my $ListenerOraDir = exists $ENV{ListenerOraDir} ? $ENV{ListenerOraDir} : $UNDEFINED;

        my $Machine = getVIPName( $CRS_HOME, $hostName );

        my $cmd = "$CRS_HOME/bin/srvctl config listener -l $LsnrName -S 1";
        my ( $err, $output ) = executeCommand( $cmd, $CRS_HOME );
        EMD_PERL_DEBUG("$LOG_CATEGORY doListenerDiscovery-> $cmd returned (err=$err, output=$output)");

    if($err eq "")
    {
     my @lns = split /\n/, $output;
     for my $ln (@lns)
     {
      if ($ln =~ /res_name\s*=\s*\{.*?\.$LsnrName\..*?\}.*?oh\s*=\s*\{(.*?)\}.*?ports\s*=\s*\{(.*?)\}/i)
       {
        $OracleHome = $1;
        $Port = $2;
        EMD_PERL_DEBUG("$LOG_CATEGORY doListenerDiscovery-> OracleHome: $OracleHome, Port: $Port");
        last;
       }
     }
    }
    
    $ListenerOraDir = $ENV{TNS_ADMIN};
    EMD_PERL_DEBUG("$LOG_CATEGORY doListenerDiscovery-> Env TNS_ADMIN: $ListenerOraDir");
    
    if(! -e ($ListenerOraDir."/listener.ora") )
    {
    	EMD_PERL_DEBUG("$LOG_CATEGORY doListenerDiscovery-> Listener.ora not exist at env TNS ADMIN loc");
    	$ListenerOraDir = getDefaultTNSAdmin($OracleHome);
    }
    
    EMD_PERL_DEBUG("$LOG_CATEGORY doListenerDiscovery-> ListenerOraDir: $ListenerOraDir");
	
	print "<Target TYPE=\"oracle_listener\" NAME=\"$UNDEFINED\" >\n";
	print "<Property NAME=\"ListenerOraDir\" VALUE=\"$ListenerOraDir\" />\n";
	print "<Property NAME=\"LsnrName\" VALUE=\"$LsnrName\" />\n";
	print "<Property NAME=\"Machine\" VALUE=\"$Machine\" />\n";
	print "<Property NAME=\"OracleHome\" VALUE=\"$OracleHome\" />\n";
	print "<Property NAME=\"Port\" VALUE=\"$Port\" />\n";
	print "</Target>\n";

}

sub doASMDiscovery {
	
	print "<Target TYPE=\"osm_instance\" NAME=\"$UNDEFINED\" >\n",
    "<Property NAME=\"OracleHome\" VALUE=\"$UNDEFINED\" />\n",
    "<Property NAME=\"Port\" VALUE=\"$UNDEFINED\" />\n",
    "<Property NAME=\"SID\" VALUE=\"$UNDEFINED\"/> \n",
    "</Target>\n";

}

sub getVIPName {
	my ( $oh, $host ) = @_;
	my $vipn      = $host;
	my $localnode = "";
	my $cmd;
	my ( $err, $output ) = ( "", "" );
	$cmd = "$oh/bin/srvctl config vip -n $ENV{NODE_NAME}";
	( $err, $output ) = executeCommand( $cmd, $oh );
	EMD_PERL_DEBUG("$LOG_CATEGORY getVIPName-> $cmd returned (err=$err, output=$output)");

    if($err ne ""){
     return $vipn;	
    }
     
	my @lns = split /\n/, $output;
    for my $ln (@lns)
    {
     if ($ln =~ /VIP exists.*?\/(.*?)\/(.*?)\//)
      {
       $vipn = ($1 eq "")? $2 : $1;
       last;
      }
    }
   
   EMD_PERL_DEBUG("$LOG_CATEGORY getVIPName-> $vipn");
   
	$vipn;
}


# 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, $oh ) = @_;
	$ENV{ORACLE_HOME} = $oh;
	my $err    = "";
	my $output = "";

	if ( open( CMDOUTPUT, "$cmd 2>&1 |" ) ) {
		my @outputs = <CMDOUTPUT>;
		$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\": $!";
	}

	EMD_PERL_ERROR("executeCommand: $cmd: $err") if ( $err ne "" );

	( $err, $output );
}

sub unset_lib_path_env {
	delete $ENV{LD_LIBRARY_PATH};
	delete $ENV{SHLIB_PATH};
	delete $ENV{LIBPATH};
	delete $ENV{DYLD_LIBRARY_PATH};
}
