# $Header: has/install/crsconfig/crspatch.pm /st_has_11.2.0/6 2011/07/14 20:21:07 xyuan Exp $ # # crspatch.pm # # Copyright (c) 2007, 2011, Oracle and/or its affiliates. All rights reserved. # =head1 NAME crspatch.pm Oracle clusterware Patching Module/Package =head1 DESCRIPTION This package contains functions required for patching Oracle clusterware Software =cut # MODIFIED (MM/DD/YY) # xyuan 07/11/11 - Fix bug 12701521 # sidshank 06/09/11 - Adding norestart option to crspatch # xyuan 06/01/11 - Add add_localOlr_OlrConfig_OcrConfig to # Instantiatepatchfiles (fix bug 12587677) # shullur 05/11/11 - For handling CHM out-of-place patching.Bug 11852891. # ksviswan 05/16/11 - Fix Bugs 12553820,12550187 # ksviswan 04/13/11 - XbranchMerge ksviswan_opauto_segregate from main # ksviswan 03/08/11 - opatch auto segregation # ksviswan 09/23/10 - Part fix for bug 10119895 # ksviswan 09/21/10 - Merge fix for bugs 9482228,9750739 # dpham 06/30/10 - Add arguement to create_dirs() and set_file_perms() # functions (9850696) # ksviswan 08/24/09 - Fix Bug 8797450 # dpham 07/29/09 - XbranchMerge dpham_bug-8727340 from # st_has_11.2.0.1.0 # ksviswan 07/24/09 - Install ACFS after patching # dpham 07/15/09 - XbranchMerge dpham_bug-8664938 from main # dpham 07/09/09 - wait for crs to start # ksviswan 04/20/09 - Creation package crspatch; use strict; use English; use File::Spec::Functions; use crsconfig_lib; use oraacfs; use constant CRSPATCH_SUCCESS => 1; use constant CRSPATCH_FAIL => 0; use Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK); @ISA = qw(Exporter); my @exp_func = qw(Stopdbhomeres Startdbhomeres patchcrssetup patchsihasetup findHomes findHomeType getcrshome isSIHA getcrsversion isServerready checkClusterstat checkdbhomestat getoracleowner isClusterwareup CRSPatch CRSPatchhome HAPatch ispathShared error trace system_cmd_capture run_as_user2 unlockCRSHomeforpatch read_file unlockHAHomeforpatch Instantiatepatchfiles StartCRS StartHA); my @exp_const = qw(CRSPATCH_SUCCESS CRSPATCH_FAIL); push @EXPORT, @exp_func, @exp_const; =head1 EXPORTED FUNCTIONS =head2 Stopdbhomeres Stop all the database home resources that are managed by Grid Infrastructure. =head3 Parameters 1. Database home path 2. Type of Database home. Is it a RAC database home or an Oracle Restart managed database home 3. Owner of the database home =head3 Returns CRSPATCH_SUCCESS - Successfully stopped all database home resources CRSPATCH_FAIL - Failed to stop all database home resources =cut sub Stopdbhomeres { my $home = $_[0]; my $sihadb = $_[1]; my $ohown = $_[2]; my $srvctlbin = catfile ($home, "bin", "srvctl"); my $nodename = $CFG->HOST; my $success = CRSPATCH_SUCCESS; my $cmd; my @output; my $status; my $stfile = catfile ($home, "srvm", "admin", "stophome.txt"); $ENV{ORACLE_HOME} = $home; #Bug 10226636 if (-e $stfile) { unlink $stfile; } if ( ! $sihadb) { $cmd = "$srvctlbin stop home -o $home -s $stfile -n $nodename"; } else { $cmd = "$srvctlbin stop home -o $home -s $stfile"; } $status = run_as_user2($ohown, \@output, $cmd ); trace("$cmd output is @output"); if ($status != 0) { error("Failed to stop resources from database home $home"); $success = CRSPATCH_FAIL; } else { trace("Stopped resources from datbase home $home"); } return $success; } =head2 Statusdbhomeres Reports the Status of all database home resources that are managed by Grid Infrastructure. =head3 Parameters 1. Database home path 2. Type of Database home. Is it a RAC database home or an Oracle Restart managed database home 3. Node Name for which the status is required =head3 Returns 1. exit status of srvctl status home command 2. output of srvctl status home. =cut sub Statusdbhomeres { my $home = $_[0]; my $sihadb = $_[1]; my $nodename = $_[2]; my $ohown = $_[3]; my $srvctlbin = catfile ($home, "bin", "srvctl"); my $success; my $cmd; my @output; my $status; my $stfile = catfile ($home, "srvm", "admin", "stathome.txt"); $ENV{ORACLE_HOME} = $home; #Bug 10226636 if (-e $stfile) { unlink $stfile; } if ( ! $sihadb) { $cmd = "$srvctlbin status home -o $home -s $stfile -n $nodename"; } else { $cmd = "$srvctlbin status home -o $home -s $stfile"; } $status = run_as_user2($ohown, \@output, $cmd ); trace("$cmd output is @output"); unlink ($stfile); return ($status, @output); } sub Instantiatepatchfiles { #TODO - Should we just rely on crsconfig_params or #should we derive the critical values. instantiate_scripts (); add_localOlr_OlrConfig_OcrConfig(); my @crsconfig_dirs = read_file (catfile ($ORA_CRS_HOME, 'crs', 'utl', 'crsconfig_dirs')); create_dirs (\@crsconfig_dirs); copy_wrapper_scripts (); my @crsconfig_fileperms = read_file (catfile ($ORA_CRS_HOME, 'crs', 'utl', "crsconfig_fileperms")); set_file_perms (\@crsconfig_fileperms); } sub StartCRS { my $rc; my $CRSCTL = crs_exec_path('crsctl'); trace("Starting Oracle Clusterware"); $rc = system ("$CRSCTL start crs"); if (!wait_for_stack_start(36)) { exit 1; } } sub StartHA { my $rc; my $CRSCTL = crs_exec_path('crsctl'); trace("Starting Oracle Restart"); $rc = system ("$CRSCTL start has"); # Check if the service/daemon has started trace ("Checking ohasd"); my $ohasd_running = check_service ("ohasd", 24); if ($ohasd_running) { trace ("ohasd started successfully"); } else { error ("Timed out waiting for ohasd to start."); exit 1; } } =head2 Startdbhomeres Starts all the database home resources that are managed by Grid Infrastructure. =head3 Parameters 1. Database home path 2. Type of Database home. Is it a RAC database home or an Oracle Restart managed database home 3. Owner of the database home =head3 Returns CRSPATCH_SUCCESS - Successfully stopped all database home resources CRSPATCH_FAIL - Failed to stop all database home resources =cut sub Startdbhomeres { my $home = $_[0]; my $sihadb = $_[1]; my $ohown = $_[2]; my $srvctlbin = catfile ($home, "bin", "srvctl"); my $nodename = $CFG->HOST; my $success = CRSPATCH_SUCCESS; my $cmd; my @output; my $status; my $stfile = catfile ($home, "srvm", "admin", "stophome.txt"); if ( ! $sihadb ) { $cmd = "$srvctlbin start home -o $home -s $stfile -n $nodename"; } else { $cmd = "$srvctlbin start home -o $home -s $stfile"; } $ENV{ORACLE_HOME} = $home; $status = run_as_user2($ohown, \@output, $cmd ); trace("$cmd output is @output"); if ($status != 0) { error("Failed to start resources from database home $home"); $success = CRSPATCH_FAIL; } else { trace("Started resources from datbase home $home"); } unlink ($stfile); return $success; } =head2 findHomes Gets all the database homes that are managed by Grid Infrastructure. =head3 Parameters None. =head3 Returns Returns the list of database homes managed by Grid Infrastructure. =cut sub findHomes { my @tmps = (); my $db = ""; my $oh = ""; my @ohs = (); my @ocp_ohs = (); my @ocp_databases; my $ocp_dblist; my $ocp_ohlist; my @out; my $rc; my $cmd; my $path; my %ohdb = (); my %dboh = (); my $srvctl = catfile ($ORA_CRS_HOME, "bin", "srvctl"); trace( "Looking for configured databases on node $HOST" ); @ocp_databases = `$srvctl config`; chomp @ocp_databases; $ocp_dblist = join " ", @ocp_databases; trace( "Databases configured on node $HOST are: $ocp_dblist" ); trace( "Determining ORACLE_HOME paths for configured databases" ); $ocp_ohlist = ""; @ocp_ohs = (); foreach $db ( @ocp_databases ) { #trace( "Looking at database $db" ); $cmd = "$srvctl config database -d $db"; @out = system_cmd_capture($cmd); $rc = shift @out; if ( $rc != 0 ) { trace("try with srvctl config database -v"); $cmd = "$srvctl config database -v"; @out = system_cmd_capture($cmd); $rc = shift @out; if ($rc == 0) { foreach my $str (@out) { my ($dbname, $dbhome, $dbver) = split(" ", $str); trace("db name is $dbname"); trace("db home is $dbhome"); trace("db ver is $dbver"); chomp $dbname; chomp $dbhome; $dboh{$dbname} = trim($dbhome); trace("Oracle home for database $dbname is $dboh{$dbname}"); } } else { error("Not able to retreive database home information"); exit 1; } last; } else { @tmps = grep(/Oracle home:/, @out); trace("output is @tmps"); my ($dummy, $ohpath) = split( /\:/, $tmps[0] ); $dboh{$db} = trim($ohpath); trace("Oracle home for database $db is $dboh{$db}"); } } #create hash oracle home to dbs foreach $db (keys%dboh) { if(defined($ohdb{$dboh{$db}})) { $ohdb{$dboh{$db}} = "$ohdb{$dboh{$db}}:$db"; } else { $ohdb{$dboh{$db}} = "$db"; } } #get unique oracle home list @ocp_ohs = keys%ohdb; foreach $oh (keys%ohdb) { trace( "Oracle Home $oh is configured with Database\(s\)\-\> $ohdb{$oh}"); } trace("oracle home list is @ocp_ohs"); return @ocp_ohs; } =head2 findHomeType Find the type of the Oracle Home. =head3 Parameters Oracle Home Path =head3 Returns Returns one of the following type. HA - Oracle Restart Home CRS - Oracle Grid Infrastructure home DB - Oracle database Home. =cut sub findHomeType { my $home = $_[0]; my $crshome; my $type; my $local_only = s_get_config_key("ocr", "local_only"); $crshome = getcrshome(); if (($home eq $crshome) && ($local_only =~ m/true/i)) { $type = "HA"; } elsif (($home eq $crshome) && ($local_only =~ m/false/i)) { $type = "CRS"; } else { $type = "DB"; } return $type; } =head2 getcrshome Gets the Grid Infrastructure Home path. =head3 Parameters None. =head3 Returns Returns the Oracle Grid Infrastructure Home Path =cut sub getcrshome { my $crsHome; $crsHome = s_get_olr_file ("crs_home"); if (! -e $crsHome) { error("Clusterware home location $crsHome does not exist"); exit 1; } return $crsHome; } =head2 iscrshome Check if the home path is a valid crs home =head3 Parameters Oracle Home Path =head3 Returns None =cut sub iscrshome { my $home = $_[0]; if ((-f $OLRCONFIG) && ($home ne s_get_olr_file ("crs_home"))) { error("Incorrect clusterware home path provided for -och option"); exit 1; } } =head2 isSIHA Check if an Oracle Restart home is configured =head3 Parameters None =head3 Returns None =cut sub isSIHA { my $ret= CRSPATCH_FAIL; my $local_only = get_config_key("ocr", "local_only"); if ($local_only =~ m/true/i) { $ret = CRSPATCH_SUCCESS; } return $ret; } sub get_config_key { my $src = $_[0]; my $key = $_[1]; $src =~ tr/a-z/A-Z/; my ($val, $cfgfile); if ($src eq 'OCR') { $cfgfile = $OCRCONFIG; } elsif ($src eq 'OLR') { $cfgfile = $OLRCONFIG; } open (CFGFL, "<$cfgfile") or return $val; while () { if (/^$key=(\S+)/) { $val = $1; last; } } close (CFGFL); return $val; } =head2 getcrsversion Gets the Active Version of Oracle Grid Infrastructure or Oracle Restart =head3 Parameters None =head3 Returns Version of the Grid Infrastructure or Oracle Restart =cut sub getcrsversion { my $crsctlbin = catfile ($ORA_CRS_HOME, 'bin', 'crsctl'); my @cmd; if (isSIHA()) { @cmd = ($crsctlbin, 'query', 'has', 'releaseversion'); } else { @cmd = ($crsctlbin, 'query', 'crs', 'activeversion'); } my @out = system_cmd_capture(@cmd); my $rc = shift @out; my @versionarr = (0, 0, 0, 0, 0); my $verstring = $out[0]; if ($rc == 0) { $verstring =~ m/\[(\d*)\.(\d*)\.(\d*)\.(\d*)\.(\d*)\].*$/; @versionarr = ($1, $2, $3, $4, $5); trace("crs version is @versionarr"); } else { error ("@cmd ... failed rc=$rc with message:\n @out \n"); } return @versionarr; } =head2 isServerready Check if the Grid Infrastructure is ready to start the database =head3 Parameters None =head3 Returns TRUE - If the clusterware is ready FALSE - If the clusterware is not ready =cut sub isServerready { my $crsctl = catfile ($ORA_CRS_HOME, "bin", "crsctl"); my @output; my $rc; my $retries = 360; my $ready = FALSE; my $grep_val = "STATE=ONLINE"; my @cmdout; while ( $retries) { @output = system_cmd_capture($crsctl, 'stat', 'resource', '-c' , $HOST); $rc = shift @output; @cmdout = grep(/$grep_val/, @output); if (scalar(@cmdout) > 0) { $ready = TRUE; last; } trace ("Waiting for Server assignments"); sleep (5); $retries--; } if ($ready) { trace ("Server assignments completed. Ready to start databases"); } else { error ("Timed out waiting for server assignments"); } return $ready; } =head2 checkClusterstat Check the status of clusterware stack on the remote nodes =head3 Parameters None =head3 Returns None =cut sub checkClusterstat { my $crsctl = catfile ($ORA_CRS_HOME, "bin", "crsctl"); my @output; my $rc; my $grep_val = "4537|4529|4533"; my @cmdout; my $nodelist = $CFG->params('NODE_NAME_LIST'); my @nodes = split(/,/, $nodelist); my $node; my $count = 0; foreach $node (@nodes) { if ($node !~ /\b$HOST\b/i) { @output = system_cmd_capture($crsctl, 'check', 'cluster', '-n' , $node); $rc = shift @output; @cmdout = grep(/$grep_val/, @output); if (scalar(@cmdout) > 0) { error("Clusterware stack up on node $node"); $count++; } } } if ($count == 0) { trace ("Clusterware stack is not running on remote nodes"); } else { error ("Clusterware stack is running on remote nodes"); print "Refer to opatch auto help for patching shared homes and follow the steps\n"; exit 1; } } =head2 checkdbhomestat Check the status of database home resources on the remote nodes =head3 Parameters None =head3 Returns None =cut sub checkdbhomestat { my $home = $_[0]; my $ohown = getoracleowner($home); my @cmdout; my $nodelist = $CFG->params('NODE_NAME_LIST'); my @nodes = split(/,/, $nodelist); my $node; my $count = 0; my $rc; my $retstat; foreach $node (@nodes) { if ($node !~ /\b$HOST\b/i) { @cmdout = Statusdbhomeres($home, 0, $node,$ohown); my $retstat = shift @cmdout; trace("ret code for status db home on $node is $retstat"); if (($retstat == 0) && (scalar(@cmdout) > 0)) { error("Database home resources for $home are running on node $node"); $count++; } } } if ($count == 0) { trace ("Database home resources for $home is not running on remote nodes"); } else { error ("Database home resources for $home is running on remote nodes"); print "Refer to opatch auto help for patching shared homes and follow the steps\n"; exit 1; } } =head2 getoracleowner gets the owner of the oracle home =head3 Parameters Oracle Home Path =head3 Returns Owner of the Oracle home. =cut sub getoracleowner { my $oh = $_[0]; my $getoh_ox = "$oh/bin/oracle"; my ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid( $< ); my $getoh_u; if ( -f $getoh_ox ) { my ($dev, $ino, $mode, $nlink, $uid, $gid, $rdev, $size, $atime, $mtime, $ctime, $blksize, $blocks) = stat( $getoh_ox ); ($name, $passwd, $uid, $gid, $quota, $comment, $gcos, $dir, $shell) = getpwuid( $uid ); $getoh_u = $name; trace( "Oracle user for $oh is $getoh_u" ); } else { error("unable to get oracle owner for $oh"); exit 1; } return $getoh_u; } =head2 isClusterwareup Check the status of clusterware stack on the local node =head3 Parameters None =head3 Returns TRUE - If the clusterware is running FALSE - If the clusterware is not running =cut sub isClusterwareup { my $crs_running; if (! isSIHA()) { $crs_running = check_service ("cluster", 2); } else { $crs_running = check_service ("ohasd", 2); } return $crs_running; } =head2 patchcrssetup Initial setup for patching Grid Infrastructure home =head3 Parameters 1. Location of configuration parameter file (crsconfig_params) 2. Location of platform definition file (s_crsconfig_defs) 3. Location of Log file 4. hostname 5. superuser id =head3 Returns None =cut sub patchcrssetup { my ($paramfile, $defsfile, $logfile, $HOST, $SUPERUSER) = @_; my $cfg; trace("Starting Clusterware Patch Setup"); $cfg = crsconfig_lib->new(paramfile => $paramfile, osdfile => $defsfile, crscfg_trace => TRUE, crscfg_trace_file => $logfile, HOST => $HOST, HAS_USER => $SUPERUSER, ); } =head2 patchsihasetup Initial setup for patching Oracle Restart home =head3 Parameters 1. Location of configuration parameter file (crsconfig_params) 2. Location of platform definition file (s_crsconfig_defs) 3. Location of Log file 4. hostname 5. superuser id =head3 Returns None =cut sub patchsihasetup { my ($paramfile, $defsfile, $logfile, $HOST, $SUPERUSER) = @_; my $cfg; my $sihainst = isSIHA(); trace("Starting Oracle Restart Patch Setup"); $cfg = crsconfig_lib->new(paramfile => $paramfile, osdfile => $defsfile, crscfg_trace => TRUE, crscfg_trace_file => $logfile, HOST => $HOST, IS_SIHA => $sihainst, ); } =head2 ispathShared Finds if the given path is shared across cluster nodes =head3 Parameters 1. path for which sharedness check is needed. =head3 Returns TRUE : if the path is shared FALSE: if the path is not shared. =cut sub ispathShared { my $path = $_[0]; my @capout = (); my $rc; my $user = $CFG->params('ORACLE_OWNER'); my $nodelist = $CFG->params('NODE_NAME_LIST'); my $status; my @nodes = split(/,/, $nodelist); trace("The cluster nodes are @nodes"); if (scalar(@nodes) == 1) { trace("Single node cluster"); $status = FALSE; return $status; } my $CLUVFY = catfile( $ORA_CRS_HOME, 'bin', 'cluvfy'); my @program = ($CLUVFY, 'comp ssa', '-t software', '-s' , $path , '-n', $nodelist, '-display_status'); my $status; trace("checking if path $path is shared"); # run as specific user, if requested $rc = run_as_user2($user, \@capout, @program); trace("return code for shared check is $rc"); trace("output of sharedness check is @capout"); if (scalar(grep(/EFAIL/, @capout)) > 0) { $status = ERROR; } elsif ((scalar(grep(/VFAIL/, @capout))) > 0){ $status = FALSE; } else { trace("The path $path is shared "); $status = TRUE; } return $status; } sub Getcrsconfig { } sub Getdbconfig { } sub Stopcrshomeres { } sub Stopcrs { } sub Startcrshomeres { } ###################################################################### # M A I N # ###################################################################### =head2 CRSPatch Performs post config steps for in place patching of Grid Infrastructure home =head3 Parameters A reference to a hash containing the prameter name and its value =head3 Returns None =cut sub CRSPatch { my $hash_arg = $_[0]; my $nostrtflg = 0; if(defined($$hash_arg{"norestart"})) { $nostrtflg=$$hash_arg{"norestart"}; } trace ("Patching Oracle Clusterware"); trace ("norestart flag is set to $nostrtflg"); #Instantiate the patched files. Instantiatepatchfiles (); my $SUCC_REBOOT = crspatch_install_usm(); if (! $nostrtflg) { StartCRS(); } if (1 == $SUCC_REBOOT) { print color 'bold'; print "A system reboot is recommended before using ACFS\n"; print color 'reset'; } } =head2 CRSPatchhome Performs post config steps for out of place patching of Grid Infrastructure home =head3 Parameters None =head3 Returns None =cut sub CRSPatchhome { my $destcrshome = $_[0]; my $actcrshome = s_get_olr_file ("crs_home"); stopClusterware($actcrshome, "crs"); #update olr s_validate_olrconfig($CFG->OLR_LOCATION, $destcrshome); # Perform CHM patching if (!perform_CHM_upgrade($destcrshome)) { trace("Couldn't perform CHM patching"); } CRSPatch (); } =head2 HAPatch Performs post config steps for in place patching of Oracle Restart home =head3 Parameters A reference to a hash containing the prameter name and its value =head3 Returns None =cut sub HAPatch { my $hash_arg = $_[0]; my $nostrtflg = 0; if(defined($$hash_arg{"norestart"})) { $nostrtflg=$$hash_arg{"norestart"}; } trace ("Patching Oracle Restart"); trace ("norestart flag is set to $nostrtflg"); #Instantiate the patched files. Instantiatepatchfiles (); my $SUCC_REBOOT = crspatch_install_usm(); if (! $nostrtflg) { StartHA(); } if (1 == $SUCC_REBOOT) { print color 'bold'; print "A system reboot is recommended before using ACFS\n"; print color 'reset'; } } =head2 crspatch_install_usm Install USM drivers =head3 Parameters None =head3 Returns 1: Need to reboot after installation 0: No need to reboot after installation =cut sub crspatch_install_usm { my $SUCC_REBOOT = 0; if (isACFSSupported()) { my $ret = installUSMDriver(); if (FAILED == $ret) { error ("ACFS driver install actions failed"); } else { trace ("ACFS drivers installation completed"); if (WARNING == $ret) { trace("Set reboot flag to 1"); $SUCC_REBOOT = 1; } } } return $SUCC_REBOOT; } 1;