#!/usr/local/bin/perl # # $Header: emdb/sysman/webapps/em/WEB-INF/perl/config/asmConfig.pl /st_emdbsa_11.2/4 2009/06/15 17:29:05 hasriniv Exp $ # # asmConfig.pl # # Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved. # # NAME # asmConfig.pl - # # DESCRIPTION # # # NOTES # # # MODIFIED (MM/DD/YY) # hasriniv 09/02/08 - Creation # require "emd_common.pl"; require "$ENV{EMDROOT}/sysman/admin/scripts/db/dbclone/clone_util.pl"; require "$ENV{EMDROOT}/sysman/admin/scripts/db/dbclone/db_clone.pl"; use strict; use File::Basename; use File::Copy; use File::Temp qw/ tempfile tempdir /; use File::stat; use vars qw/$hostUserID $OS $NT $S $TEMP $CP $MV $PS $DF $DELIMITER $Registry/; $ENV{EMAGENT_PERL_TRACE_LEVEL} = 0; #DEBUG level. # Global variables $hostUserID = ""; ########################################################## ## Create single instance ASM ########################################################## sub createSIAsm { EMD_PERL_DEBUG("asmConfig.createSIAsm(): Start"); my ($asmHome, $tnsAdmin, $asmSysPassword, $diskString, $listener) = @_; EMD_PERL_DEBUG("asmConfig.createSIAsm(): asmHome: $asmHome"); EMD_PERL_DEBUG("asmConfig.createSIAsm(): tnsAdmin: $tnsAdmin"); EMD_PERL_DEBUG("asmConfig.createSIAsm(): diskString: $diskString"); EMD_PERL_DEBUG("asmConfig.createSIAsm(): listener: $listener"); &set_env_var($asmHome, ""); $ENV{TNS_ADMIN} = "$tnsAdmin"; # Call dbca and create asm my($dbcaexec) = "$asmHome${S}bin${S}dbca"; #redirect output to a temp file (my $fh, my $filename) = &create_temp_file(); if($NT) { $filename = "$TEMP\\"."asmconfig.$$"; } EMD_PERL_DEBUG("asmConfig.createSIAsm(): Temp pfile: $filename"); my($cmd) = "$dbcaexec -silent -configureASM -asmSysPassword \'$asmSysPassword\' -diskString \'$diskString\' -listeners \'$listener\'"; EMD_PERL_DEBUG("asmConfig.createSIAsm(): Command: $cmd"); my(@res) = `$cmd >$filename 2>&1`; my $mesg = getOutputFromFile($filename); print STDOUT $mesg; if($?) { EMD_PERL_DEBUG("asmConfig.createSIAsm(): dbca command failed"); exit(1); } close $fh; if($NT) { &removeFile($filename); } return; } ########################################################## ## Get Disk List using kfod ########################################################## sub getDisklist { EMD_PERL_DEBUG("asmConfig.getDisklist(): Start"); my ($oracleHome, $asmDiskString, $isVersionLessThan102) = @_; EMD_PERL_DEBUG("asmConfig.getDisklist(): oracleHome: $oracleHome"); EMD_PERL_DEBUG("asmConfig.getDisklist(): asmDiskString: $asmDiskString"); EMD_PERL_DEBUG("asmConfig.getDisklist(): isVersionLessThan102: $isVersionLessThan102"); set_env_var($oracleHome, ""); my $kfodExe = "kfod"; if($NT) { $kfodExe = "kfod.exe" } my($kfodexec) = "$oracleHome${S}bin${S}$kfodExe"; if(! -e "$kfodexec") { $kfodexec = "$oracleHome${S}rdbms${S}bin${S}$kfodExe"; } #redirect output to a temp file (my $fh, my $filename) = &create_temp_file(); if($NT) { $filename = "$TEMP\\"."asmconfig.$$"; } EMD_PERL_DEBUG("asmConfig.getDisklist(): Temp pfile: $filename"); my($cmd) = ""; my $origOsmInstallSetting = $ENV{"OSM_INSTALL_TEST"}; if ($origOsmInstallSetting ne "") { $ENV{"OSM_INSTALL_TEST"} = ""; if ($isVersionLessThan102 eq "TRUE") { $cmd = "$kfodexec nohdr=TRUE OP=DISKS _asm_allow_only_raw_disks=FALSE asm_diskstring='$asmDiskString'"; } else { $cmd = "$kfodexec nohdr=TRUE OP=DISKS disks=all status=true _asm_allow_only_raw_disks=FALSE asm_diskstring='$asmDiskString'"; } EMD_PERL_DEBUG("asmConfig.getDisklist(): Command: $cmd"); my(@res) = `$cmd >$filename 2>&1`; $ENV{"OSM_INSTALL_TEST"} = $origOsmInstallSetting; } else { if ($isVersionLessThan102 eq "TRUE") { $cmd = "$kfodexec nohdr=TRUE OP=DISKS asm_diskstring='$asmDiskString'"; } else { $cmd = "$kfodexec nohdr=TRUE OP=DISKS disks=all status=true asm_diskstring='$asmDiskString'"; } EMD_PERL_DEBUG("asmConfig.getDisklist(): Command: $cmd"); my(@res) = `$cmd >$filename 2>&1`; } my $mesg = getOutputFromFile($filename); print STDOUT $mesg; if($?) { EMD_PERL_DEBUG("asmConfig.getDisklist(): kfod command failed"); exit(1); } close $fh; if($NT) { &removeFile($filename); } return; } # check if the Oracle Home is valid. # validateOracleHome(oracleHome) sub validateOracleHome { my $oracleHome = $_[0]; EMD_PERL_DEBUG("asmConfig.validateOracleHome(): the given oracleHome: $oracleHome"); my $dirExist = dirExists($oracleHome); if( $dirExist ne "OK") { EMD_PERL_DEBUG("asmConfig.validateOracleHome(): Invalid directory: $oracleHome"); return "NOK1"; } set_env_var($oracleHome, ""); my $nls_lang = $ENV{NLS_LANG}; $ENV{NLS_LANG} = 'American_America.al32utf8'; #use sqlplus to detect if this is a valid Oracle Home my @versionString = `$oracleHome/bin/sqlplus -v 2>&1`; my $versionString = "@versionString"; EMD_PERL_DEBUG("asmConfig.validateOracleHome(): versionString: $versionString"); my $sqlplusPos = index($versionString, "SQL*Plus:"); if( $sqlplusPos < 0) { EMD_PERL_DEBUG("asmConfig.validateOracleHome(): Bad SQLPLUS in Oracle Home: $oracleHome"); return "NOK3"; } if(defined($nls_lang)) { $ENV{NLS_LANG} =$nls_lang; } #the length of Recovery Manager: plus a space is 18 my $sqlVersion = trim(substr($versionString, $sqlplusPos + 18, 11)); EMD_PERL_DEBUG("asmConfig.validateOracleHome(): sqlVersion: $sqlVersion"); if(&compareVer($sqlVersion, "10.1.0.0") < 0) { EMD_PERL_DEBUG("asmConfig.validateOracleHome(): $sqlVersion is not supported to create ASM."); return "NOK4"; } if (&compareVer($sqlVersion, "11.2.0.0") > -1 ) { my $asmcaExe = "asmca"; if($NT) { $asmcaExe = "asmca.bat" } if(! -e "$oracleHome/bin/$asmcaExe") { EMD_PERL_DEBUG("asmConfig.validateOracleHome(): ASMCA executable file does not exist in Oracle Home: $oracleHome"); return "NOK2"; } } else { my $dbcaExe = "dbca"; if($NT) { $dbcaExe = "dbca.bat" } if(! -e "$oracleHome/bin/$dbcaExe") { EMD_PERL_DEBUG("asmConfig.validateOracleHome(): DBCA executable file does not exist in Oracle Home: $oracleHome"); return "NOK2"; } } my $dbs = 'dbs'; if($NT) { $dbs = 'database'; } my $dbsLocation = ${oracleHome}.${S}.${dbs}; my $wPermission = dirWritePermission($dbsLocation); if( $wPermission ne "OK") { EMD_PERL_DEBUG("asmConfig.validateOracleHome(): No write permission in: $dbsLocation"); return "NOK5"; } EMD_PERL_DEBUG("asmConfig.validateOracleHome(): Verification success"); return $sqlVersion; } # Check if an Oracle process(es) is running for the specified instance. # This check is done for linux only. For NT, it calls serviceCheck(). # Return OK if the process does not exist, otherwise, return NOK. # Need to pass in OracleHome for NT, otherwise, it returns agent's TNS_ADMIN # instanceCheck(OracleHome) sub asmInstanceCheck { EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): *** START ***"); my $oracleHome = $_[0]; my($line); if($OS ne "NT") { EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): Linux platform"); #Check: Look for running processes for this instance my(@res) = `$PS -ef 2>&1`; if(@res > 1) { EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): examining process listing"); foreach $line (@res) { chop($line); if ($line =~ /asm_.+_\+ASM$/) { EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): found process for +ASM: $line"); EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): *** END ***"); return "NOK"; } } } EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): NOT found process for +ASM"); } else { EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): OS type is $OS"); if($NT) { EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): NT platform"); return asmServiceCheck("+ASM", $oracleHome); } } EMD_PERL_DEBUG("asmConfig.asmInstanceCheck(): *** END ***"); return "OK"; } # For Linux, add an entry to oratab for asm instance. # addEntryAsmToOratab() sub addAsmEntryToOratab { EMD_PERL_DEBUG("asmConfig.addEntryAsmToOratab(): *** START ***"); if(!$NT) { my($oratab) = getOratab(); EMD_PERL_DEBUG("asmConfig.addEntryAsmToOratab(): Adding an entry to oratab: $oratab"); #temp handle no oratab case if($oratab eq "") { EMD_PERL_DEBUG("asmConfig.addEntryAsmToOratab(): oratab does not exist"); return; } if (-w "$oratab") { my $oracleHome = $ENV{ORACLE_HOME}; my $instance = "+ASM"; #$ENV{ORACLE_SID}; EMD_PERL_DEBUG("asmConfig.addEntryAsmToOratab(): Examining oratab file for instance $instance"); #if an instance with the same name is running, abort my $chkStatus = &asmInstanceCheck($oracleHome); if($chkStatus eq "NOK") { EMD_PERL_ERROR("asmConfig.addEntryAsmToOratab(): Could not add $instance to $oratab"); my(@res) = `$PS -ef 2>&1`; my $line; if(@res > 1) { print STDOUT "$PS -ef | grep ora_ | grep _+ASM\n"; foreach $line (@res) { chop($line); if ($line =~ /asm_.+_\+ASM$/) { print STDOUT "$line\n"; } } } exit(1); } #Allow reusing existing SID $chkStatus = &oratabCheck("\\+ASM"); if($chkStatus eq "NOK") { #comment out the original line &commentOutEntryInOratab("\\+ASM"); } open(ORATAB, ">>$oratab") || die "Cannot open $oratab"; #Append the new entry to oratab file print ORATAB "${instance}:${oracleHome}:N\n"; close ORATAB || die "Cannot close $oratab"; } else { EMD_PERL_ERROR("asmConfig.addEntryAsmToOratab(): NO write permission to file $oratab"); #should we add the entry to a temp file and notify users? } } else { EMD_PERL_DEBUG("asmConfig.addEntryAsmToOratab(): NT platform, no need to add entry to oratab"); } EMD_PERL_DEBUG("asmConfig.addEntryAsmToOratab(): *** END ***"); } # Check if asm service already exists for the specified instance. # This check is done for NT only. # Return OK if the service does not exist, otherwise, return NOK. # serviceCheck(inst, OracleHome) sub asmServiceCheck { EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): *** START ***"); my($instance) = $_[0]; my $passedInOracleHome = $_[1]; if($NT) { #Check: Look for existing service for this instance by checking the registry. my $oracleHome = $ENV{ORACLE_HOME}; if(defined($passedInOracleHome)) { $oracleHome = $passedInOracleHome; } EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): Oracle Home: $oracleHome, Instance: $instance"); my $service_value= $Registry->{"LMachine${S}System${S}CurrentControlSet${S}Services${S}OracleASMService${instance}${S}ImagePath"} or EMD_PERL_DEBUG("Can not find the service for LMachine${S}System${S}CurrentControlSet${S}Services${S}OracleASMService${instance}${S}ImagePath: $^E"); if(!defined $service_value) { EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): NOT found service for $instance"); EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): *** END ***"); return "OK"; } EMD_PERL_ERROR("asmConfig.asmServiceCheck(): Found service for $instance !!!"); EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): registry value: $service_value"); EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): *** END ***"); return "LMachine${S}System${S}CurrentControlSet${S}Services${S}OracleASMService${instance}${S}ImagePath: $service_value"; } else { EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): NOT NT platform"); } EMD_PERL_DEBUG("asmConfig.asmServiceCheck(): *** END ***"); return "OK"; } # runOradimAsm() sub runOradimAsm { EMD_PERL_DEBUG("asmConfig.runOradimAsm(): *** START ***"); if($NT) { my $oracleHome = $ENV{ORACLE_HOME}; my $instance = $ENV{ORACLE_SID}; my $runAs = ""; if ($hostUserID ne "") { $runAs = " -RUNAS ".$hostUserID; } EMD_PERL_DEBUG("asmConfig.runOradimAsm(): Running oradim to install service for $instance"); my($cmd) = "${oracleHome}${S}bin${S}oradim.exe -NEW -ASMSID $instance -STARTMODE auto -SRVCSTART system "; EMD_PERL_DEBUG("asmConfig.runOradimAsm(): Command: ${cmd}"); $cmd = $cmd.$runAs; &tempLocFallback(); my $filename = "$TEMP\\"."asmConfig.$$"; EMD_PERL_DEBUG("asmConfig.runOradimAsm(): Output file: $filename"); # Do NOT check the return value of this command my(@res) = `$cmd >$filename 2>&1`; if($?) { my($err) = "@res"; EMD_PERL_ERROR("asmConfig.runOradimAsm(): ${oracleHome}${S}bin${S}oradim.exe -NEW -ASMSID $instance -STARTMODE auto -SRVCSTART system: $err"); exit(1); } &removeFile($filename); EMD_PERL_DEBUG("asmConfig.runOradimAsm(): service for $instance has been started"); } else { EMD_PERL_DEBUG("asmConfig.runOradimAsm(): Not NT platform, no need to run oradim"); } EMD_PERL_DEBUG("asmConfig.runOradimAsm(): *** END ***"); } # Run specified SQL script file or text # Call &set_env_var($oracleHome, $oracleSid) before calling this method. # run112AsmScript(userName,password,script) sub run112AsmScript { EMD_PERL_DEBUG("asmConfig.run112AsmScript(): *** START ***"); my ($username,$password,$script) = @_; EMD_PERL_DEBUG("asmConfig.run112AsmScript(): script: $script"); my $sql_string = ""; $sql_string .= "set echo on\n"; $sql_string .= "$script\n"; $sql_string .= "exit;\n"; (my $fh, my $filename) = &runSqlOnAsm($username,$password,"sysasm",$sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("asmConfig.run112AsmScript(): *** END ***"); } # Run specified SQL script file or text # Call &set_env_var($oracleHome, $oracleSid) before calling this method. # runPre112AsmScript(userName,password,script) sub runPre112AsmScript { EMD_PERL_DEBUG("asmConfig.runPre112AsmScript(): *** START ***"); my ($username,$password,$script) = @_; EMD_PERL_DEBUG("asmConfig.runPre112AsmScript(): script: $script"); my $sql_string = ""; $sql_string .= "set echo on\n"; $sql_string .= "$script\n"; $sql_string .= "exit;\n"; (my $fh, my $filename) = &runSqlOnAsm($username,$password,"sysdba",$sql_string); close $fh; if($NT) { &removeFile($filename); } EMD_PERL_DEBUG("asmConfig.runPre112AsmScript(): *** END ***"); } # Run given sql script on destination oracleHome # The caller is responsible to close the returned fileHandle # runSqlOnAsm(sqlScript, hideOutput) will hide standard output for any # defined parameter "hideOutput" # runSqlOnAsm(username,password,dbrole,sqlScript, hideOutput, hideSQL) will hide standard # output for any defined parameter "hideOutput" and SQL script for any defined # parameter "hideSQL" # runSqlOnAsm(sqlScript) will print standard output sub runSqlOnAsm { EMD_PERL_DEBUG("asmConfig.runSqlOnAsm(): *** START ***"); my ($userID) = $_[0]."/".$_[1]; my ($sql_string) = $_[3]; my ($dbRole) = ""; if (!defined($_[2]) || $_[2] eq "") { $dbRole = "sysasm"; } else { $dbRole = $_[2]; } if(!defined($_[5])) { EMD_PERL_DEBUG("asmConfig.runSqlOnAsm(): SQL:\n$sql_string"); } (my $fh, my $filename) = &create_temp_file(); if($NT) { $filename = "$TEMP\\"."dbclone.$$"; } # If a username/password had been specified, use it. Otherwise, # default to OS authentication if($userID){ EMD_PERL_DEBUG("asmConfig.runSqlOnAsm(): Connecting with connect descriptor"); open(SQL_SCRIPT, "|$ENV{ORACLE_HOME}/bin/sqlplus /nolog >$filename") || die "Cannot open pipe for SQL_SCRIPT"; print SQL_SCRIPT "CONNECT $userID AS $dbRole;\n"; } else{ EMD_PERL_DEBUG("asmConfig.runSqlOnAsm(): Connecting with OS auth"); open(SQL_SCRIPT, "|$ENV{ORACLE_HOME}/bin/sqlplus '/ AS $dbRole' >$filename") || die "Cannot open pipe for SQL_SCRIPT"; } print SQL_SCRIPT $sql_string; ## close SQL_SCRIPT || die "Bad SQL_SCRIPT"; close SQL_SCRIPT || die "Bad SQL_SCRIPT : sqlplus exited with $?"; #Open the temp file to print output to standard output and debug trace file open (OUT_PUT, "$filename") || die "Unable to open tempfile for OUT_PUT\n"; my @output_content = ; my $output_string = "@output_content"; close OUT_PUT; if(!defined($_[4])) { print STDOUT $output_string; } EMD_PERL_DEBUG("asmConfig.runSqlOnAsm(): OUT_PUT:\n$output_string"); &parseOutput($output_string); EMD_PERL_DEBUG("asmConfig.runSqlOnAsm(): *** END ***"); return ($fh, $filename); } sub getASMInstances { my ($oh) = @_; my $cmd = "$oh/bin/srvctl status asm -S 1"; my ( $err, $output ) = executeCommand( $cmd, $oh ); EMD_PERL_DEBUG("$cmd returned (err=$err, output=$output)"); my @instance_name_array = (); if($err eq "") { my @lns = split /\n/, $output; for my $ln (@lns) { if ($ln =~ /inst_name={(.*)} node_name={(.*?)} /) { my $res = "$1:$2"; push(@instance_name_array, $res); } } } my $instance_names = join (",", @instance_name_array); ($instance_names); } sub executeCommand { my ( $cmd, $oh ) = @_; $ENV{ORACLE_HOME} = $oh; 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\": $!"; } ( $err, $output ); } #Takes in array of diskgroup names and mounts them # at all the nodes of a cluster # Applicable when oracle home version is 11.2 or above sub mountDGsOnAllNodes { my ( $dgList, $oh ) = @_; my $separator = ","; my @diskGroups = split /$separator/, $dgList; my $cmd = ""; for my $diskGroup (@diskGroups) { $cmd = "$oh/bin/srvctl start diskgroup"; $cmd = $cmd . " -g $diskGroup"; my ( $err, $output ) = executeCommand( $cmd, $oh ); EMD_PERL_DEBUG("$cmd returned (err=$err, output=$output)"); } } 1;