#!/usr/local/bin/perl
# 
# $Header: rac_srvctl.pl 22-dec-2005.12:21:48 ysun Exp $
#
# rac_srvctl.pl
# 
# Copyright (c) 2002, 2005, Oracle. All rights reserved.  
#
#    NAME
#      rac_srvctl.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)
#    ysun        12/22/05 - support 10.1OMS and 10.2agent
#    vkapur      08/24/05 - fix bug 4572452 
#    vkapur      11/03/04 - show success msg for job 
#    vkapur      10/25/04 - fixes for job support 
#    vkapur      10/13/04 - support calling startup_rac, shutdown_rac for 
#                           start/shut jobs 
#    xuliu       10/07/04 - xuliu_mov_rac_f
#    vkapur      09/17/04 - R2 features: add,modify,remove 
#    vkapur      03/05/04 - NT fix 3486880 
#    xuliu       03/01/04 - fix 3469118 
#    vkapur      01/22/04 - NT fix: add doAll check
#    vkapur      09/03/03 - NT switch for password piping
#    vkapur      07/28/03 - error report for startup/shutdown
#    ysun        07/08/03 - provide absolute path
#    ysun        07/01/03 - pipe password
#    vkapur      06/17/03 - mod version check
#    vkapur      06/10/03 - add get_db_status, get_db_config
#    vkapur      06/06/03 - improve error handling
#    vkapur      04/17/03 - fix relocate string
#    vkapur      04/07/03 - correct version check, more services functions
#    vkapur      03/20/03 - add services
#    ysun        08/20/02 - handle connection string   
#    ysun        07/30/02 - ysun_rac_srvctl_support
#    ysun        07/30/02 - Creation
# 

use Cwd;
require "$ENV{EMDROOT}/sysman/admin/scripts/db/db_common.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/db/dbstate.pl";
require "$ENV{EMDROOT}/sysman/admin/scripts/semd_common.pl";
$statexe = '$ENV{ORACLE_HOME}/bin/srvctl';

#get_rac_version();
#get_rac_status($dbName);   # dbName
#startup_rac($dbName, $option, $connStr, $sidList);    
#get_rac_status($dbName);   # dbName
#shutdown_rac($dbName, $option, $connStr, $sidList);  

sub get_exec_env
{
    # chomp ($version = `$ENV{ORACLE_HOME}/bin/srvctl`)
    # chomp ($version = `$ENV{ORACLE_HOME}/bin/lsnodes`)
    chomp ($version = `echo $ENV{ORACLE_HOME}`)
      or die 'Failed to echo';
    print $version."\n";
    chomp ($version = `echo $ENV{JAVA_HOME}`)
      or die 'Failed to echo';
    print $version."\n";
}

sub get_srvctl_version
{
    $cmd = "$ENV{ORACLE_HOME}/bin/srvctl config -V";

    chomp ($result = `$cmd`);
    if ($? != 0) {
##	   print 'Failed to run the srvctl command in get_rac_version';
	print "$result\n";
	return ($? >> 8);
    }

##    chomp ($version = `$ENV{ORACLE_HOME}/bin/srvctl config -V`)
##      or die "Failed to run the srvctl command in get_rac_version, ORACLE_HOME = $oh";

    # for services, require at least 10i
    # for startup/shutdown, require at least 9.2 version

    if ($result =~ /10/)
    {
	$version = '10';  
	print $version;
	return;
    }
    if ( $result =~ /9.2/)
    {
        $version='92';
    }
    else 
    {
        $version='90';
    }

    print "$version";

    return has_ec($result);
}

### to be deprecated:
sub get_rac_version
{
   chomp ($version = `$ENV{ORACLE_HOME}/bin/srvctl config -V`)
     or die "Failed to run the srvctl command in get_rac_version";

    # for services, require at least 10i
    # for startup/shutdown, require at least 9.2 version

    if ($version =~ /10/)
    {
        $serv_version = '10';
	$version = '92';  # for start/shut, 9.2 and 10 are treated same
	return;
    }

    if ( $version =~ /9.2/)
    {
        $serv_version = '92';
        $version='92';
    }
    else 
    {
	$serv_version = '90';
        $version='90';
    }
}

sub get_rac_status
{
    my $dbName = $_[0];
    if ( $version =='92' )
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl config database -d ".$dbName;

	chomp ($result = `$cmd`)
           or die 'Failed to get db config';

        print "\{".$result."\}\n";

        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl status database -S 1 -d ".$dbName;

	chomp ($result = `$cmd`)
           or die 'Failed to run the srvctl command in get_rac_status';

    }
    if ( $version =='90' )
    {
    }
    
    print $result."\n";
}

sub get_db_status
{
    my $dbName = $_[0];
    if ( $version =='92' || $version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl status database -S 1 -d ".$dbName;

	chomp ($result = `$cmd`);
	if ($? != 0) {
##	   print 'Failed to run the srvctl command in get_db_status';
	    print "$result\n";
	    return ($? >> 8);
	}
    }
    if ( $version =='90' )
    {
    }
    
    print $result."\n";

    return has_ec($result);
}


sub get_db_config
{
    my $dbName = $_[0];
    if ( $version =='92' || $version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl config database -d ".$dbName;

	chomp ($result = `$cmd`);
	if ($? != 0) {
##	    die 'Failed to run the srvctl command in get_db_config';
	    print "$result\n";
	    return ($? >> 8);
	}
    }
    if ( $version =='90' )
    {
    }
    
    print $result."\n";

    return has_ec($result);
}

#
# startup_rac: wrapper around dbstate.pl
#              Starts RAC database on ALL instances.
#              Used for startup/shutdown job support in 10.2
#
# dbName:  RAC database name
# startupOption:  {open, mount, nomount} [force] [restrict] [read only]
# connStr, instanceList, doAll are ignored (kept for backward compatibility with 10.1 agent)
# oracleHome: ORACLE_HOME for database
# localSID:   local instance name for host where this fcn is invoked
#
sub startup_rac
{
    my ($dbName, $startupOption, $connStr, $instanceList, $doAll, $oracleHome, $localSID) = @_;
    if ( !$oracleHome ) {
        $oracleHome=$ENV{ORACLE_HOME};
    }

    # connStr, instanceList are ignored (kept for backward compatibility with 10.1 agent)

    my $dbUsername = "";
    my $dbPassword = "";
    my $dbRole = "SYSDBA";
    my $targetType = "rac_database";
    my $tns = "";
    $instanceList = "";
    my $isDB10i = 1;
    my $sqlRunState = "";
    my $restoreDBState = 0;
    my $initState = "";
    my $bounceAfterPostSQL = 0;
    my @postStartupSql;

    # call to dbstate.pl 
    $exitCode = startup_db($targetType, $oracleHome, $localSID, $dbName, $dbUsername, $dbPassword, $dbRole, $tns, $instanceList, $isDB10i, $startupOption, $sqlRunState, $restoreDBState, $initState, $bounceAfterPostSQL, @postStartupSql);
    if ($exitCode == 0) {
	print "Startup successful on all nodes.\n";
    }
    return $exitCode;
}

#
# shutdown_rac: wrapper around dbstate.pl
#              Stops RAC database on ALL instances.
#              Used for startup/shutdown job support in 10.2
#
# dbName:  RAC database name
# shutdownOption:  {immediate, transactional, normal, abort}
# connStr, instanceList are ignored (kept for backward compatibility with 10.1 agent)
# oracleHome: ORACLE_HOME for database
# localSID:   local instance name for host where this fcn is invoked
#
sub shutdown_rac
{
#    my ($oracleHome, $dbName, $dbUsername, $dbPassword, $dbRole, $localSID, $shutdownOption) = @_;
    my ($dbName, $shutdownOption, $connStr, $instanceList, $doAll, $oracleHome, $localSID) = @_;
    if ( !$oracleHome ) {
        $oracleHome=$ENV{ORACLE_HOME};
    }

    # connStr, instanceList are ignored (kept for backward compatibility with 10.1 agent)

    my $dbUsername = "";
    my $dbPassword = "";
    my $dbRole = "SYSDBA";
    my $targetType = "rac_database";
    my $tns = "";
    $instanceList = "";
    my $isDB10i = 1;
    my $restoreDBState = 0;
    my $initState = "";
    my $bounceAfterPostSQL = 0;
    my @preShutdownSql;

    # call to dbstate.pl 
    $exitCode = shutdown_db($targetType, $oracleHome, $localSID, $dbName, $dbUsername, $dbPassword, $dbRole, $tns, $instanceList, $isDB10i, $shutdownOption, $restoreDBState, $initState, @preShutdownSql);
    if ($exitCode == 0) {
	print "Shutdown successful on all nodes.\n";
    }
    return $exitCode;
}


#########################  Services #############################

# note: Rac Services functionality is only for 10i db


# Usage: get_service_status(dbName, [sv1...svK])
# Calls: srvctl status service -f -S 1 -d dbName -s sv1,sv2...svK

sub get_service_status
{
    my ($dbName, $sv_names) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl status service -f -S 1 -d ".$dbName." -s ".$sv_names;

	print "Srvctl command: $cmd\n";

        ##	if (system "$cmd") {
	chomp ($result = `$cmd`);
	if ($? != 0) {
##	    print "Failed to run the srvctl command in get_service_status\n";
	    print "$result\n";
	    return ($? >> 8);
	}
    }

    print $result."\n";

    return has_ec($result);
}


# Usage: get_service_config(dbName, [sv1...svK])
# Calls: srvctl config service -S 1 -d dbName -s [sv1,...,svK]

sub get_service_config
{
    my ($dbName, $sv_names) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
	if ($sv_names) {
	    $cmd = "$ENV{ORACLE_HOME}/bin/srvctl config service -S 1 -d $dbName -s $sv_names";
	}
	else {
	    $cmd = "$ENV{ORACLE_HOME}/bin/srvctl config service -S 1 -d ".$dbName;
	}

	print "Srvctl command: $cmd\n";

	## if (system "$cmd") {
	chomp ($result = `$cmd`);
	if ($? != 0) {
	    print "$result\n";
##	    print "Failed to run the srvctl command in get_service_config\n";
	    return ($? >> 8);
	}
    }

    print $result."\n";

    return has_ec($result);
}


# Usage: do_service_add(dbName, servName, pref_list, avail_list, taf_policy)
# Calls: srvctl add service -d dbName -s servName -r <pref_list> -a <avail_list> -P <taf_policy>
sub do_service_add
{
    my ($dbName, $servName, $pref_list, $avail_list, $taf_policy) = @_;

    if ($version == '10') {
	$cmd = "$ENV{ORACLE_HOME}/bin/srvctl add service -d $dbName -s $servName -r $pref_list";


	if ($avail_list) {
	    $cmd = $cmd." -a $avail_list";
	}

	$cmd = $cmd." -P $taf_policy";

	print "Srvctl command: $cmd\n";
	chomp ($result = `$cmd`);
	if ($? != 0) {
	    print "$result\n";
	    return ($? >> 8);
       }
    }

    print $result."\n";

    return has_ec($result);	
}


# Usage: do_service_modify(dbName, servName, pref_list, avail_list, taf_policy)
# Calls: srvctl modify service -d dbName -s servName -n -i <pref_list> -a <avail_list> -P <taf_policy>
sub do_service_modify
{
    my ($dbName, $servName, $pref_list, $avail_list, $taf_policy) = @_;

    if ($version == '10') {
	$cmd = "$ENV{ORACLE_HOME}/bin/srvctl modify service -d $dbName -s $servName -n -i $pref_list";


	if ($avail_list) {
	    $cmd = $cmd." -a $avail_list";
	}

#	$cmd = $cmd." -P $taf_policy";

	print "Srvctl command: $cmd\n";
	chomp ($result = `$cmd`);
	if ($? != 0) {
	    print "$result\n";
	    return ($? >> 8);
       }

       # modify taf policy:
	$cmd = "$ENV{ORACLE_HOME}/bin/srvctl modify service -d $dbName -s $servName -P $taf_policy";
	print "Srvctl command: $cmd\n";
	chomp ($taf_result = `$cmd`);
	if ($? != 0) {
	    print "$taf_result\n";
	    return ($? >> 8);
       }
    }

    print "$result \n $taf_result \n";

    return has_ec($result);	
}

# Usage: do_service_remove(dbName, servName, doDisconnect)
# Calls: srvctl remove service -d dbName -s servName [-f]
sub do_service_remove
{
    my ($dbName, $servName, $doDisconnect) = @_;

    if ($version == '10') {
	$cmd = "$ENV{ORACLE_HOME}/bin/srvctl remove service -d $dbName -s $servName -f";

	print "Srvctl command: $cmd\n";
	chomp ($result = `$cmd`);
	if ($? != 0) {
	    print "$result\n";
	    return ($? >> 8);
       }
    }

    return has_ec($result);	
}


# Usage: do_service_enable(dbName, [sv1...svK], inst_name)
# Calls: srvctl enable service -d dbName -s [sv1,...,svK] -i inst_name
# Requires: inst_name, if specified, must be registered to all [sv1...svk]

sub do_service_enable
{
    my ($dbName, $sv_names, $inst_name) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl enable service -d ".$dbName." -s $sv_names";

	# add instance (if it was passed in):
	if ($inst_name)
	{
	    $cmd = $cmd." -i $inst_name";
	}

	print $cmd."\n";

        ### if (system "$cmd") {
	chomp ($result = `$cmd`);
	if ($? != 0) {
##	    print "Failed to run the srvctl command in do_service_start\n";
	    print "$result\n";
	    return ($? >> 8);
       }
    }

    print $result."\n";

    return has_ec($result);
}


# Usage: do_service_disable(dbName, [sv1...svK], inst_name)
# Calls: srvctl disable service -d dbName -s [sv1,...,svK] -i inst_name
# Requires: inst_name, if specified, must be registered to all [sv1...svk]

sub do_service_disable
{
    my ($dbName, $sv_names, $inst_name) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl disable service -d ".$dbName." -s $sv_names";

	# add instance (if it was passed in):
	if ($inst_name)
	{
	    $cmd = $cmd." -i $inst_name";
	}

	print "Srvctl command: $cmd\n";

        ## if (system "$cmd") {
	chomp ($result = `$cmd`);
	if ($? != 0) {
##           print 'Failed to run the srvctl command in do_service_disable';
	    print "$result\n";
	    return ($? >> 8);
       }
    }

    print $result."\n";

    return has_ec($result);
}


# Usage: do_service_start(dbName, [sv1...svK], inst_name)
# Calls: srvctl start service -d dbName -s [sv1,...,svK] -i inst_name
# Requires: inst_name, if specified, must be registered to all [sv1...svk]

sub do_service_start
{
    my ($dbName, $sv_names, $inst_name) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl start service -d ".$dbName." -s $sv_names";

	# add instance (if it was passed in):
	if ($inst_name)
	{
	    $cmd = $cmd." -i $inst_name";
	}

	print "Srvctl command: $cmd\n";

#	if ($ec = system "$cmd") {
	chomp ($result = `$cmd`);
	if ($? != 0) {
##	    print 'Failed to run the srvctl command in do_service_start';
	    print "$result\n";
	    return ($? >> 8);
	}
    }

    print $result."\n";
#    print "result = $result\n";

    return has_ec($result);
}


# Usage: do_service_stop(dbName, [sv1...svK], inst_name, [doDisconnect])
# Calls: srvctl stop service -d dbName -s [sv1,...,svK] -i inst_name [-f]
# Requires: inst_name, if specified, must be registered to all [sv1...svk]

sub do_service_stop
{
    my ($dbName, $sv_names, $inst_name, $doDisconnect) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl stop service -d ".$dbName." -s $sv_names";

	# add instance (if it was passed in):
	if ($inst_name)
	{
	    $cmd = $cmd." -i $inst_name";
	}

	if ($doDisconnect) {
	    $cmd = $cmd." -f";
	}

	print "Srvctl command: $cmd\n";

        ###	if (system "$cmd") {
        chomp ($result = `$cmd`);
	if ($? != 0) {
##	    print 'Failed to run the srvctl command in do_service_stop';
	    print "$result\n";
	    return ($? >> 8);
	}
    }

    print $result."\n";

    return has_ec($result);
}


# Usage: do_service_relocate(dbName, sv_name, from_inst, to_inst)
# Calls: srvctl relocate service -d dbName -s sv_name -i from_inst -t to_inst
# Requires: sv_name is currently running on from_inst, and to_inst is a 
#           registered instance

sub do_service_relocate
{
    my ($dbName, $sv_name, $from_inst, $to_inst) = @_;

#    if ( $serv_version =='10' )
    if ($version=='10')
    {
        $cmd = "$ENV{ORACLE_HOME}/bin/srvctl relocate service -d ".$dbName." -s $sv_name -i $from_inst -t $to_inst";

	print "Srvctl command: $cmd\n";

        ##	if (system "$cmd") {
        chomp ($result = `$cmd`);
	if ($? != 0) {
##          print  'Failed to run the srvctl command in do_service_relocate';
	    print "$result\n";
	    return ($? >> 8);
       }
    }

    print $result."\n";

    return has_ec($result);
}


# Purpose: find following error codes in input string:
#          "PRKP"
#          "PRKH"
#          "PRKO"
#          "CRS"
#          "ORA"
sub has_ec
{
    $in_str = $_[0];

#    print "error code detector: $in_str\n";

    if ($in_str =~ /PRKP-/ || $in_str =~ /PRKH-/ || $in_str =~ /PRKO-/ || $in_str =~ /CRS-/ || $in_str =~ /ORA-/) {
	return(-1);  # error mesg
    }
    else {
	return(0);
    }
    
}


## 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
##
# Return the original current dir if it's changed
# Otherwise return ""
sub changeCWDForSrvctlIfNecessary
{
    my ($oracleHome, $srvctlVersion) = @_;
    my $orgDIR = "";
    
    if (get_osType() eq 'WIN' && $srvctlVersion eq '92')
    {    
        # This is a NT pre-10g srvctl
        $orgDIR = getcwd;
        chdir "$oracleHome/bin";
    }
    
    $orgDIR;
}

