# Copyright (c) 2011, 2016, 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 10/31/16 - Backport xyuan_bug-24692493 from main # xyuan 10/10/16 - Fix bug 24692493 # xyuan 08/10/16 - Fix bug 24413197 # muhe 07/24/16 - Fix bug 23094557 # xyuan 07/14/16 - Fix bug 23733697 # xyuan 06/26/16 - Fix bug 23633680 # bbeelamk 06/07/16 - Limit s_reset_crshome method only to deinstall # muhe 05/19/16 - Fix bug 23279387 # bbeelamk 05/18/16 - Fix bug 23233230 # muhe 04/27/16 - Install XAG component for OOP patching # ssprasad 03/24/16 - Rename runAFDtool to afdScanDevices # muhe 02/04/16 - Fix bug 22140295 # ksviswan 12/03/15 - copy config data is done by rhp # xyuan 11/26/15 - Fix bug 22200719 # xyuan 11/03/15 - Fix bug 22135419 # bbeelamk 10/06/15 - Fix bug 21878673 # xyuan 08/07/15 - Fix bug 21562230 # luoli 07/24/15 - make "-transferfile" optional for writing global # CKPT and global CKPT property # muhe 07/09/15 - Fix bug 21047431 # xyuan 07/08/15 - Fix bug 21306584 # shullur 06/24/15 - For CHM migration modules to new rootscript changes # luoli 06/15/15 - Change print_error to print_info when printing # success information # ksviswan 06/10/15 - move ACFS module init # ksviswan 05/19/15 - move copyConfigurationData to crscpcfg.pm # muhe 04/14/15 - Add pre checks for patch # xyuan 04/13/15 - Clean-ups # madoming 03/16/15 - Changes for new framework # nkorehis 02/25/15 - bug-20185476: call rscPreChecks # bbeelamk 02/06/15 - Fix bug 20465849 # bbeelamk 02/05/15 - Fix bug 20465662 # muhe 02/03/15 - Fix bug 20373088 # xyuan 01/22/15 - Fix bug 20130937 # sbezawad 12/22/14 - Bug 20019354: Migrate OCR and OLR to new framework # bbeelamk 11/13/14 - Fix bug 20006646 # ssprasad 11/11/14 - AFD disk rescan - perform explicitly # ssprasad 09/29/14 - Check if AFD installed instead of supported # muhe 09/25/14 - Fix bug 19683886 # jmarcias 09/17/14 - Fix bug 19325613 # muhe 09/14/14 - Fix bug 19513650 # rdasari 09/12/14 - touch the oc4j ear files in postpatch # muhe 09/05/14 - Get the "-rollback" option from the command line # rdasari 05/29/14 - modify 10.2 db resources bug 18708349 # xyuan 04/17/14 - Fix bug 18606913 # muhe 04/03/14 - Fix bug 16801852 # xyuan 03/31/14 - Make sure no GI processes running after shutting # down the stack during prepatch # xyuan 01/20/14 - Fix bug 17602658 - move setCRSResourceUseAttr to # crsutils.pm # ssprasad 01/16/14 - AFD specific actions during patching # xyuan 01/01/14 - Fix bug 17881823 # xyuan 12/13/13 - Fix bug 17818075 # xyuan 11/26/13 - Fix bug 17838960 # madoming 11/22/13 - Fix bug 17841639 # rdasari 11/12/13 - do not use exclude file for SIHA unlock # madoming 10/28/13 - Add validation for current working directory # xyuan 10/08/13 - Fig bug 17560365 # xyuan 09/30/13 - Fix bug 17513885 - forward merge the code for # patching mgmtdb # cnagur 09/24/13 - TFA Setup # xyuan 09/15/13 - Fix bug 17444212 # bamorale 08/20/13 - bug17340646 proxy is added only when needed # shmubeen 08/16/13 - Bug# 17262330 # xyuan 07/23/13 - Fix bug 16542792 # shmubeen 07/08/13 - remove ORA_ENABLE_AFD_INSTALL check # xyuan 06/30/13 - Fix bug 16850372 # xyuan 06/30/13 - Fix bug 16913646 # xyuan 04/17/13 - Fix bug 16670327 # xyuan 03/31/13 - XbranchMerge xyuan_bug-16515209_win from # st_has_12.1.0.1 # xyuan 03/20/13 - Fix bug 16515209 - delete the existing OHASD service # before starting the new stack if OOP patching # madoming 01/30/13 - Try to enable asm proxy only when ACFS is supported # xyuan 01/30/13 - Fix bug 16084403 # xyuan 01/07/13 - XbranchMerge xyuan_bug-16032732 from # st_has_12.1.0.1 # xyuan 01/06/13 - XbranchMerge xyuan_bug-16026674 from # st_has_12.1.0.1 # shullur 12/25/12 - Forward merge of shullur_bug-13968580 # xyuan 12/23/12 - Fix bug 16032732 # xyuan 12/20/12 - set env var ORAASM_UPGRADE in sub # getActivePatchLevel & getSoftwarePatch # xyuan 11/22/12 - Fix bug 14845507 # ssprasad 11/13/12 - Disable OKA actions for 12.1 # ssprasad 10/22/12 - Add OKA actions for patching. # xyuan 10/16/12 - Fix checkpoint issues introduced when adding afd # patching # xyuan 10/16/12 - Fix bug 14747053 # xyuan 09/03/12 - Fix bug 14568610 - reset postatch checkpoints for # different patch scenarios # shmubeen 07/31/12 - add afd patching # xyuan 08/02/12 - Fix a typo in the trace message # xyuan 07/31/12 - Fix bug 14374241 # xyuan 07/24/12 - Fix bug 14313040 # rtamezd 06/19/12 - Use print_lines() # xyuan 06/07/12 - Disable/enable CRS resources only for '-norestart' # rtamezd 05/16/12 - Fix bug 14068782 # anjiwaji 05/08/12 - Rename # createACFSDriversResource->actionDriversResource # and pass in an action # sidshank 05/03/12 - remove s_redirect/restore output subroutines # xyuan 03/25/12 - Fix bug 13867795 # xyuan 03/25/12 - Fix bug 13872932 # xyuan 03/25/12 - Fix bug 13879808 # xyuan 02/27/12 - Remove unnecessary subroutines # xyuan 02/20/12 - New patching interfaces for 12c # rtamezd 01/11/12 - Fix bug 13576465 # anjiwaji 12/14/11 - Create and start driver resource after patching. # shullur 11/03/11 - XbranchMerge shullur_bug_11852891 from # st_has_11.2.0 # xesquive 08/15/11 - forward merge from bug-12587677 # xyuan 07/27/11 - XbranchMerge xyuan_bug-12701521 from # st_has_11.2.0.3.0 # 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 Term::ANSIColor; use Cwd; use constant CRSPATCH_SUCCESS => 1; use constant CRSPATCH_FAIL => 0; # root scripts modules use crsutils; use crsgpnp; use s_crsutils; use oraacfs; use crska; use crsupgrade; use oraafd; use crstfa; use oraClusterwareComp; use oraolr; use oraocr; use s_oraolr; use s_oraocr; use crsxag; # export functions use Exporter; use vars qw(@ISA @EXPORT @EXPORT_OK); @ISA = qw(Exporter); my @exp_const = qw(CRSPATCH_SUCCESS CRSPATCH_FAIL); my @exp_func = qw(lockHome unlockSIHAPatchHome unlockCRSPatchHome); push @EXPORT, @exp_const, @exp_func; sub new { shift; crsutils->new(@_); rscPreChecks(); $CFG->compACFS(oraClusterwareComp::oraacfs->new("ACFS")); ($CFG->compACFS)->prePatchCheck(); if ($CFG->ROLLBACK) { trace("'-rollback' option passed. Doing patch rollback."); } # patch if ($CFG->PREPATCH) { if ($CFG->CLEANPIDS) { trace("Attempt to terminate active GI processes"); my %pids = findActiveGIProcs(); my @pidsArry = (keys %pids); trace("Attempt to terminate the following processes [@pidsArry]"); termActiveGIProcs(\%pids); exit(0); } if ($CFG->SIHA) { unlockHAHomeforpatch(); } else { crsPrePatch(); } } elsif ($CFG->POSTPATCH) { if (($CFG->DESTCRSHOME) && (($CFG->params('ORACLE_HOME')) ne ($CFG->DESTCRSHOME))) { my $dsthome = $CFG->DESTCRSHOME; trace("The ORACLE_HOME parameter should be identical to " . "the destination home during postpatch for OOP patching"); $ENV{'ORACLE_HOME'} = $dsthome; $CFG->ORA_CRS_HOME($dsthome); $CFG->params('ORACLE_HOME', $dsthome); $CFG->params('CRFHOME', $dsthome); $CFG->params('JREDIR', "$dsthome/jdk/jre/"); $CFG->params('JLIBDIR', "$dsthome/jlib"); } if ($CFG->SIHA) { HAPatch(); } else { crsPostPatch(); } } elsif ($CFG->GIMOVE) # The option for changing the GI home path { if ($CFG->SIHA) { HAPatch(); } else { changeGIHomePath(); } } } sub changeGIHomePath { $CFG->NONROLLING(TRUE); $CFG->NORESTART(FALSE); crsPostPatch(); } sub Instantiatepatchfiles { instantiate_scripts (); add_localOlr_OlrConfig_OcrConfig(); my @crsconfig_dirs = read_file (catfile($CFG->ORA_CRS_HOME, 'crs', 'utl', $CFG->HOST, 'crsconfig_dirs')); create_dirs (\@crsconfig_dirs); copy_wrapper_scripts (); my @crsconfig_fileperms = read_file (catfile($CFG->ORA_CRS_HOME, 'crs', 'utl', $CFG->HOST, 'crsconfig_fileperms')); set_file_perms (\@crsconfig_fileperms); # Set owner/group of ORA_CRS_HOME and its parent dir to root/dba if (! is_dev_env() && (! $CFG->SIHA) && ($CFG->platform_family eq "unix")) { s_setParentDirOwner ($CFG->SUPERUSER, $CFG->ORA_CRS_HOME); } my $envfile = 's_crsconfig_' . $CFG->HOST . '_env.txt'; my $envtxt = catfile($CFG->ORA_CRS_HOME, 'crs', 'install', $envfile); if (($CFG->platform_family eq "unix") && (! -e $envtxt)) { trace("Create the env file for Clusterware daemons"); s_createConfigEnvFile(); } # Set the ownership/permission of olr if ($CFG->SIHA) { s_set_ownergroup ($CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP'), $CFG->OLR_LOCATION); } else { s_set_ownergroup ($CFG->SUPERUSER, $CFG->params('ORA_DBA_GROUP'), $CFG->OLR_LOCATION); } s_set_perms ("0600", $CFG->OLR_LOCATION); # copy afd to init/rc directories if(isAFDInstalled()) { s_copy_afdinit_init(); } #copy init.ohad,ohasd to init/rc dirs s_register_service('ohasd'); # Update OHASD service file if ($CFG->platform_family eq "unix") { s_update_ohasd_service() || die(dieformat(318)); } } ###################################################################### # M A I N # ###################################################################### sub installPatchedScripts { my $SUCC_REBOOT = 0; if (! isCkptexist("ROOTCRS_POSTPATCH_LOCKDSTHOME")) { writeCkpt("ROOTCRS_POSTPATCH_LOCKDSTHOME", CKPTSTART); $CFG->wipCkptName("ROOTCRS_POSTPATCH_LOCKDSTHOME"); } if (! isCkptSuccess("ROOTCRS_POSTPATCH_LOCKDSTHOME")) { $CFG->wipCkptName("ROOTCRS_POSTPATCH_LOCKDSTHOME"); trace("Instantiating and installing patched files"); # Instantiate the patched files. Instantiatepatchfiles(); writeCkpt("ROOTCRS_POSTPATCH_LOCKDSTHOME", CKPTSUC); $CFG->wipCkptName("ROOTCRS_POSTPATCH"); } if (! isCkptexist("ROOTCRS_POSTPATCH_AFDINST")) { writeCkpt("ROOTCRS_POSTPATCH_AFDINST", CKPTSTART); $CFG->wipCkptName("ROOTCRS_POSTPATCH_AFDINST"); } if (! isCkptSuccess("ROOTCRS_POSTPATCH_AFDINST")) { $CFG->wipCkptName("ROOTCRS_POSTPATCH_AFDINST"); # Bug21562230 - Make sure ACFS has been unloaded before # re-installing AFD crspatch_uninstall_usm(); trace("Installing AFD drivers ..."); $SUCC_REBOOT = crspatch_install_afd(); if (REBOOT == $SUCC_REBOOT) { set_bold(); die(dieformat(400)); reset_bold(); } writeCkpt("ROOTCRS_POSTPATCH_AFDINST", CKPTSUC); $CFG->wipCkptName("ROOTCRS_POSTPATCH"); } if (! isCkptexist("ROOTCRS_POSTPATCH_ACFSINST")) { writeCkpt("ROOTCRS_POSTPATCH_ACFSINST", CKPTSTART); $CFG->wipCkptName("ROOTCRS_POSTPATCH_ACFSINST"); } if (! isCkptSuccess("ROOTCRS_POSTPATCH_ACFSINST")) { $CFG->wipCkptName("ROOTCRS_POSTPATCH_ACFSINST"); trace("Installing ACFS drivers ..."); $SUCC_REBOOT = crspatch_install_usm("crs"); if (1 == $SUCC_REBOOT) { set_bold(); die(dieformat(400)); reset_bold(); } writeCkpt("ROOTCRS_POSTPATCH_ACFSINST", CKPTSUC); $CFG->wipCkptName("ROOTCRS_POSTPATCH"); } # # NOTE: This is commented out for 12.1 Post 12.1 # branching, it will be enabled. # #if (! isCkptexist("ROOTCRS_POSTPATCH_OKAINST")) #{ # writeCkpt("ROOTCRS_POSTPATCH_OKAINST", CKPTSTART); # $CFG->wipCkptName("ROOTCRS_POSTPATCH_OKAINST"); #} # #if (! isCkptSuccess("ROOTCRS_POSTPATCH_OKAINST")) #{ # $CFG->wipCkptName("ROOTCRS_POSTPATCH_OKAINST"); # # trace("Installing OKA drivers ..."); # # # NOTE: Only for reboot failures, we will # # exit. For rest of the failures, we # # continue. Later, during resource OKA start, # # we could fail and there too, we continue. # # # $SUCC_REBOOT = crspatch_install_oka(); # if (1 == $SUCC_REBOOT) # { # set_bold(); # die(dieformat(400)); # reset_bold(); # } # # writeCkpt("ROOTCRS_POSTPATCH_OKAINST", CKPTSUC); # $CFG->wipCkptName("ROOTCRS_POSTPATCH"); #} } =head2 perform_oop_steps Performs post config steps for out of place patching of Grid Infrastructure home =head3 Parameters [0] CRS home to be patched =head3 Returns None =cut sub perform_oop_steps { my $patchGIHome = $_[0]; my $oraolr = $CFG->compOLR; my $orachm = $CFG->compCHM; # Perform CHM patching if (!$orachm->perform_CHM_upgrade($patchGIHome)) { trace("Failed to patch Cluster Health Monitor."); print_error(408); } # update olr.loc $oraolr->validate_olrconfig($CFG->OLR_LOCATION, $patchGIHome); } =head2 HAPatch Performs post config steps for in place patching of Oracle Restart home =head3 Parameters None =head3 Returns None =cut sub HAPatch { trace ("Patching Oracle Restart"); my $configuredHAHome = s_get_olr_file("crs_home"); my $patchHAHome = ($CFG->DESTCRSHOME) ? ($CFG->DESTCRSHOME) : $configuredHAHome; $CFG->compOLR(oraClusterwareComp::oraolr->new("OLR")); $CFG->compOCR(oraClusterwareComp::oraocr->new("OCR")); my $oraolr = $CFG->compOLR; trace("Configured HA home: $configuredHAHome"); trace("Patched HA home: $patchHAHome"); if ($CFG->DESTCRSHOME) { trace("Stopping Oracle Restart stack for out-of-place patching ..."); stopFullStack_SIHA("force", $configuredHAHome) || die(dieformat(348)); # update olr.loc trace("update olr.loc for SIHA out-of-place patching..."); $oraolr->validate_olrconfig($CFG->OLR_LOCATION, $patchHAHome); } #Instantiate the patched files. Instantiatepatchfiles(); my $SUCC_REBOOT_AFD = crspatch_install_afd(); my $SUCC_REBOOT = crspatch_install_usm("has"); clscfgLocalPatch($patchHAHome) || die(dieformat(180, 'clscfg -localpatch')); if (! $CFG->NORESTART) { startSihaStack() || die(dieformat(318)); } if (1 == $SUCC_REBOOT) { print color 'bold'; print_info(400); print color 'reset'; } if (REBOOT == $SUCC_REBOOT_AFD) { print color 'bold'; print_info(400); print color 'reset'; } } sub crspatch_uninstall_usm { trace("Deinstalling ACFS drivers ..."); ($CFG->compACFS)->deconfigureNonLastNode(); } =head2 crspatch_install_usm Install USM drivers =head3 Parameters $1 : has/crs - this signifies the patch is patching Oracle Restart or RAC. =head3 Returns 1: Need to reboot after installation 0: No need to reboot after installation =cut sub crspatch_install_usm { my $SUCC_REBOOT = 0; my $has = $_[0]; trace("Installing ACFS drivers to system root"); my $oraacfs = $CFG->compACFS; my $ret = $oraacfs->configureFirstNode($oraacfs->INSTALL_ACFS); if (FAILED == $ret) { die(dieformat(196)); } elsif (REBOOT == $ret) { trace("ACFS drivers cannot be installed, and reboot may resolve this"); $SUCC_REBOOT = 1; } else { trace("ACFS drivers installation completed"); } return $SUCC_REBOOT; } =head2 crspatch_install_oka Install OKA drivers =head3 Parameters =head3 Returns 1: Need to reboot after installation 0: No need to reboot after installation =cut sub crspatch_install_oka { my $SUCC_REBOOT = 0; my $has = "crs"; if (isOKASupported()) { trace("Installing OKA drivers to system root"); my $ret = installOKADriver($has); if (REBOOT == $ret) { trace("OKA drivers cannot be installed, and reboot may resolve this"); $SUCC_REBOOT = 1; } elsif (SUCCESS == $ret) { trace("OKA drivers installation completed"); } else { trace("OKA drivers cannot be installed, proceeding with rest of the patch action"); } } else { trace("OKA is not supported"); } return $SUCC_REBOOT; } =head2 crspatch_install_afd Install AF drivers =head3 Returns REBOOT(3): Need to reboot after installation 0: No need to reboot after installation =cut sub crspatch_install_afd { my $SUCC_REBOOT = 0; my $ret; if (isAFDInstalled()) { trace("Installing ASM Filter driver to system root"); $ret = installAFDriver(); if (FAILED == $ret) { die(dieformat(2501)); } elsif (REBOOT == $ret) { trace("ASM Filter driver cannot be installed and reboot may resolve this"); $SUCC_REBOOT = REBOOT; } else { trace("ASM Filter driver patching completed"); # Run 'asmcmd afd_scan' to inform AF Driver about managed devices. afdScanDevices(); } } else { trace("AFD is not installed"); } return $SUCC_REBOOT; } sub unlockHAHomeforpatch { unlockSIHAPatchHome(); } sub unlockInPlaceGIHome { my $unlock_home = $_[0]; trace("Unlocking the GI Home (inplace) for patching: $unlock_home"); unlockHome($CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP'), 755, $unlock_home); print_info(347, $unlock_home); } sub unlockSIHAPatchHome { trace ("Unlock Oracle Restart home..."); my $unlock_hahome; my $status = SUCCESS; if (!$CFG->UNLOCK) { $CFG->UNLOCK(TRUE); } #Try to get the home path from olr.loc my $configuredHAHome = s_get_olr_file("crs_home"); $unlock_hahome = ($CFG->DESTCRSHOME) ? ($CFG->DESTCRSHOME) : $configuredHAHome; trace("Configured HA home: $configuredHAHome"); trace("HA home to unlock: $unlock_hahome"); if ($CFG->DESTCRSHOME && ($unlock_hahome eq $configuredHAHome)) { trace("The destination HA home should not be the same as the " ."configured HA home"); die(dieformat(432)); } # validate if crshome exists if (! -e $unlock_hahome) { print_error(46, $unlock_hahome); trace ("Oracle Restart home: $unlock_hahome not found\n"); return FALSE; } if ($CFG->DESTCRSHOME) { my $paramfile = catfile($unlock_hahome, "crs", "install", "crsconfig_params"); modifyparamfile("ORACLE_HOME", $unlock_hahome, $paramfile); modifyparamfile("CRFHOME", $unlock_hahome, $paramfile); modifyparamfile("JREDIR", "$unlock_hahome/jdk/jre/", $paramfile); modifyparamfile("JLIBDIR", "$unlock_hahome/jlib", $paramfile); # set new home instantiate prior to unlock $ENV{'ORACLE_HOME'} = $unlock_hahome; $CFG->ORA_CRS_HOME($unlock_hahome); $CFG->params('ORACLE_HOME', $unlock_hahome); $CFG->params('CRFHOME', $unlock_hahome); $CFG->params('JREDIR', "$unlock_hahome/jdk/jre/"); $CFG->params('JLIBDIR', "$unlock_hahome/jlib"); # instantiate prior to unlock instantiate_scripts($unlock_hahome); } if (! $CFG->DESTCRSHOME) { $status = stopOracleRestart(); } # check the status of HA stack if ($status) { #Unlock all dirs which are in crsconfig_dirs.sbs file unlockHome($CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP'), 755, $unlock_hahome); #The full home is reset when the unlock is done #in the context of deinstall. if ($CFG->defined_param('HOME_TYPE')) { #Unlock all the files of oracle home except #the files which are in install.excl file. s_reset_crshome($CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP'), 755, $unlock_hahome); } print_info(347, $unlock_hahome); } else { print_error(348); } } sub unlockCRSPatchHome { my $dstHome = $_[0] ? $_[0] : $CFG->DESTCRSHOME; trace ("Unlock Oracle CRS home..."); $CFG->compOLR(oraClusterwareComp::oraolr->new("OLR")); $CFG->compOCR(oraClusterwareComp::oraocr->new("OCR")); if (!$CFG->UNLOCK) { $CFG->UNLOCK(TRUE); } my $activeHome = s_get_olr_file("crs_home"); my $unlock_home = $dstHome ? $dstHome : $activeHome; if ($CFG->DESTCRSHOME && ($unlock_home eq $activeHome)) { trace("The destination CRS home should not be the same as the " ."configured CRS home"); die(dieformat(432)); } if (! -e $unlock_home) { trace("The Oracle home to unlock doesn't exist"); die(dieformat(46, $unlock_home)); } if ($dstHome) { trace("Unlocking the GI home: $unlock_home"); my $paramfile = catfile($unlock_home, "crs", "install", "crsconfig_params"); modifyparamfile("ORACLE_HOME", $unlock_home, $paramfile); modifyparamfile("CRFHOME", $unlock_home, $paramfile); modifyparamfile("JREDIR", "$unlock_home/jdk/jre/", $paramfile); modifyparamfile("JLIBDIR", "$unlock_home/jlib", $paramfile); # set new home instantiate prior to unlock $ENV{'ORACLE_HOME'} = $unlock_home; $CFG->ORA_CRS_HOME($unlock_home); $CFG->params('ORACLE_HOME', $unlock_home); $CFG->params('CRFHOME', $unlock_home); $CFG->params('JREDIR', "$unlock_home/jdk/jre/"); $CFG->params('JLIBDIR', "$unlock_home/jlib"); # instantiate prior to unlock instantiate_scripts($unlock_home); my $cdataDir = catfile($unlock_home, 'cdata'); my $olrPath = $cdataDir; $CFG->OLR_LOCATION(catfile($olrPath, $CFG->HOST . '.olr')); add_localOlr_OlrConfig_OcrConfig(); my @crsconfig_dirs = read_file(catfile($CFG->ORA_CRS_HOME, 'crs', 'utl', $CFG->HOST, 'crsconfig_dirs')); create_dirs(\@crsconfig_dirs); copy_wrapper_scripts(); my @crsconfig_fileperms = read_file(catfile($CFG->ORA_CRS_HOME, 'crs', 'utl', $CFG->HOST, 'crsconfig_fileperms')); set_file_perms(\@crsconfig_fileperms); } else { trace ("unlock GI home is $unlock_home"); if (!$CFG->DESTCRSHOME) { stopClusterware($unlock_home, "crs"); } } #Shutdown TFA shutdown_tfa(); #Unlock all dirs which are in crsconfig_dirs.sbs file unlockHome($CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP'), 755, $unlock_home); #The full home is reset when the unlock is done #in the context of deinstall. if ($CFG->defined_param('HOME_TYPE')) { #Unlock all the files of oracle home except #the files which are install.excl file s_reset_crshome($CFG->params('ORACLE_OWNER'), $CFG->params('ORA_DBA_GROUP'), 755, $unlock_home); } print_info(347, $unlock_home); } sub lockHome { trace("Locking Oracle home ..."); $CFG->compOLR(oraClusterwareComp::oraolr->new("OLR")); my $oraolr = $CFG->compOLR; if (!$CFG->LOCK) { $CFG->LOCK(TRUE); } my $activeHome = s_get_olr_file("crs_home"); my $dstHome = $CFG->DESTCRSHOME; my $lockHome = $dstHome ? $dstHome : $activeHome; trace("Active Oracle home: $activeHome"); trace("The Oracle home to lock is: $lockHome"); if ($dstHome) { if ($lockHome eq $activeHome) { trace("The destination home should not be the same as the " ."configured home for lock"); die(dieformat(432)); } trace("Shutting down the running stack from $activeHome ..."); if ($CFG->SIHA) { stopFullStack_SIHA("force", $activeHome) || die(dieformat(348)); } else { stopFullStack("force", $activeHome) || die(dieformat(349)); shutdown_tfa(); } trace("Update olr.loc for crs_home to point to the dest"); $oraolr->validate_olrconfig($CFG->OLR_LOCATION, $lockHome); } # Lock Oracle home Instantiatepatchfiles(); # Keep the stack down for '-lock' option } ################################################################# ## Function to integrate pre-patch steps for GI Home ## -prepatch [-nonrolling] [-norestart] [-destcrshome] ################################################################# sub crsPrePatch { trace("Performing the pre-patching steps required for GI stack ..."); my $configuredGIHome = s_get_olr_file("crs_home"); if (! $configuredGIHome) { trace("Software only home patching. No operation for prepatch."); return SUCCESS; } my $patchGIHome = ($CFG->DESTCRSHOME) ? ($CFG->DESTCRSHOME) : $configuredGIHome; my $dstcrshome = $CFG->DESTCRSHOME; trace("Destination CRS home: $dstcrshome"); trace("Configured GI home: $configuredGIHome"); trace("GI Home to be patched: $patchGIHome"); if (($CFG->DESTCRSHOME) && ($patchGIHome eq $configuredGIHome)) { trace("The destination GI home is same as the configured " ."GI home for out-of-place GI home patching"); print_info(901); exit(0); } # check if middle of upgrade then abort the patch if ( ($CFG->params('ASM_UPGRADE') =~ m/true/i) && ((! isCkptexist("ROOTCRS_LASTNODE", "-global")) || (CKPTSUC ne getCkptStatus("ROOTCRS_LASTNODE", "-global"))) ) { trace("Patch is aborted because upgrade is in progress"); die(dieformat(235)); } if (! $CFG->NONROLLING) { prechecksForRollingPatch($configuredGIHome); } $CFG->compOLR(oraClusterwareComp::oraolr->new("OLR")); $CFG->compOCR(oraClusterwareComp::oraocr->new("OCR")); my $oraolr = $CFG->compOLR; my $oraocr = $CFG->compOCR; my $olrCompName = $oraolr->compName; my $ocrCompName = $oraocr->compName; $oraolr->prePatchCheck() || die(dieformat(607, $olrCompName)); $oraocr->prePatchCheck() || die(dieformat(607, $ocrCompName)); crsPrePatchCkpts(); ## if out-of-place patching if ($CFG->DESTCRSHOME) { trace("Preparing the destination GI home for out-of-place patching ..."); unlockCRSPatchHome($patchGIHome); trace("Done - Performing pre-pathching steps required for GI stack"); writeCkpt("ROOTCRS_PREPATCH", CKPTSUC); return SUCCESS; } ## if in-place patching my $stackUp = checkGIStack($configuredGIHome); trace("Preparing the GI stack for in-place patching ..."); $stackUp = performPrePatch($configuredGIHome, $stackUp); # Unconditionally stop stack trace("Stopping Oracle Clusterware stack ..."); stopFullStack("force", $configuredGIHome) || die(dieformat(349)); my %activeProcs; for (my $i = 0; $i < 36; $i++) { sleep(10); trace("Checking if there are still GI processes running ..."); %activeProcs = findActiveGIProcs(); if (0 == scalar(keys %activeProcs)) { trace("Successfully stopped the Oracle Clusterware stack"); last; } } if (scalar(keys %activeProcs) > 0) { my @pids = keys %activeProcs; trace("Some GI processes are still active [@pids]"); my $pidslist = join(',', @pids); die(dieformat(546, $pidslist)); } ## Have an API to check if crsctl is use by EM GC. ## Use fuser crsctl to find processes # Shut down TFA shutdown_tfa(); trace("Unlocking the GI home $patchGIHome for patching ..."); unlockInPlaceGIHome($patchGIHome); trace("Done - Performing pre-pathching steps required for GI stack"); writeCkpt("ROOTCRS_PREPATCH", CKPTSUC); return SUCCESS; } #################################################################### # This function peforms the following tasks: # If rolling: # 1) The Software Patch Level will be updated in OLR for rollback, # if the Release Patch Level does not match Software Patch Level. # 2) Starts the GI stack if required # 3) Runs 'crsctl start rollingpatch' # else if '-norestart' && stack is not up: # Starts OHASD only # # If '-norestart': # Sets CRSD to not start application resources #################################################################### sub performPrePatch { my $patchGIHome = $_[0]; my $stackUp = $_[1]; trace("Patch GI home: '$patchGIHome'"); if (! $CFG->NONROLLING) { my $softwarepatch = getSoftwarePatchOLR($patchGIHome); trace("Software Patch Level (OLR): $softwarepatch"); writeCkptProperty("ROOTCRS_PREPATCH", "SOFTWAREPATCH", $softwarepatch); if ($CFG->ROLLBACK) { my $releasepatch = getReleasePatch($patchGIHome); trace("Release Patch Level: $releasepatch"); if (trim($releasepatch) ne trim($softwarepatch)) { # Bug 22140295: # The Software Patch Level (OLR) will not be same as the Release Patch # Level if there is a failure in postpatch before the Software Patch # Level (OLR) was updated. A subsequent rollback will fail due to # mismatched patch levels. # Update the Software Patch Level (OLR) outside -postpatch. trace("Clusterware Release Patch Level does not match Software " ."Patch Level (OLR)."); trace("Updating the Software Patch Level in OLR outside postpatch"); clscfgLocalPatch($patchGIHome) || die(dieformat(180, 'clscfg -localpatch')); } } if (GI_STACK_UP != $stackUp) { # Make sure the stack is completely down before starting it stopFullStack("force", $patchGIHome) || die(dieformat(349)); trace("Starting Oracle Clusterware stack to begin rolling patch..."); startFullStack($patchGIHome) || die(dieformat(117)); $stackUp = GI_STACK_UP; } # Show cluster active patch level before rolling patch my $CRSCTL = catfile($patchGIHome, 'bin', 'crsctl'); system_cmd($CRSCTL, 'query', 'crs', 'activeversion', '-f'); trace("Setting the GI stack for rolling patch application ..."); startRollingPatch($patchGIHome) || die(dieformat(430)); } return $stackUp; } #################################################################### # This function peforms the following tasks: # 1) Call perfromPrePatch if OOP patching # 2) Stop old stack if needed before switching to the new stack # 3) Lock destination GI home # 4) Update software patch level in OLR using 'clscfg -localpatch' # 5) Start the stack from destination GI home # 6) Update software patch level in OCR using 'clscfg -patch' # 7) Run 'crsctl stop rollingpatch' # 8) actionACFSDriversResource # 9) actionOKADriversResource # 10) Install XAG component # 11) Enable CRS resources and stop the stack if 'norestart' is specified #################################################################### sub performPostPatch { my $configuredGIHome = $_[0]; my $patchGIHome = $_[1]; trace("Configured GI home: '$configuredGIHome'"); trace("patch GI home: '$patchGIHome'"); my $stackUp = checkGIStack($configuredGIHome); ## if out-of-place & rolling patching if ($CFG->DESTCRSHOME) { if (! isCkptexist("ROOTCRS_POSTPATCH_OOP_PRESTEPS")) { writeCkpt("ROOTCRS_POSTPATCH_OOP_PRESTEPS", CKPTSTART); $CFG->wipCkptName("ROOTCRS_POSTPATCH_OOP_PRESTEPS"); } if (! isCkptSuccess("ROOTCRS_POSTPATCH_OOP_PRESTEPS")) { $CFG->wipCkptName("ROOTCRS_POSTPATCH_OOP_PRESTEPS"); trace("Perform steps required for preparing GI stack for out-of-place patching"); $stackUp = performPrePatch($configuredGIHome, $stackUp); writeCkpt("ROOTCRS_POSTPATCH_OOP_PRESTEPS", CKPTSUC); $CFG->wipCkptName("ROOTCRS_POSTPATCH"); } } ## Must stop old stack trace("Stopping Oracle Clusterware stack ..."); stopFullStack("force", $configuredGIHome) || die(dieformat(349)); #Patch TFA patch_tfa($configuredGIHome,$patchGIHome); if ($CFG->DESTCRSHOME) { if (! isCkptexist("ROOTCRS_POSTPATCH_OOP_REQSTEPS")) { writeCkpt("ROOTCRS_POSTPATCH_OOP_REQSTEPS", CKPTSTART); $CFG->wipCkptName("ROOTCRS_POSTPATCH_OOP_REQSTEPS"); } if (! isCkptSuccess("ROOTCRS_POSTPATCH_OOP_REQSTEPS")) { $CFG->wipCkptName("ROOTCRS_POSTPATCH_OOP_REQSTEPS"); trace("Performing steps required for out-of-place patching ..."); perform_oop_steps($patchGIHome); if ($CFG->platform_family eq "windows") { s_deltService("OracleOHService"); s_deltService("OracleMGMTDBService-MGMTDB"); s_delete_Oracle_Services("OracleAPXService\\+APX", $configuredGIHome); s_delete_Oracle_Services("OracleASMService\\+ASM", $configuredGIHome); } writeCkpt("ROOTCRS_POSTPATCH_OOP_REQSTEPS", CKPTSUC); $CFG->wipCkptName("ROOTCRS_POSTPATCH"); } } installPatchedScripts(); if ($CFG->DESTCRSHOME) { trace("OOP patching: retrieve current releasepatch level"); my $releasepatch = getReleasePatch($patchGIHome); trace("Write current releasepatch level [$releasepatch] into checkpoints"); writeCkptProperty("ROOTCRS_POSTPATCH", "RELEASEPATCH", $releasepatch); } ## Call the following block for rolling and non-rolling cases clscfgLocalPatch($patchGIHome) || die(dieformat(180, 'clscfg -localpatch')); if ($CFG->NORESTART) { trace("OHASD needs to be up for disabling CRS resource"); startOhasdOnly($patchGIHome) || die(dieformat(117)); trace("Set the attribute to start CRS without starting the resources"); setCRSResourceUseAttr($patchGIHome, 'disable') || die(dieformat(180, 'crsctl set resource use')); # OHASD must be stopped before starting the full stack stopFullStack("force", $patchGIHome) || die(dieformat(349)); } # modify OC4J files to fix bug 19602208 modifyOC4JFiles($patchGIHome); trace("Starting Oracle Clusterware stack for rolling patch ..."); startFullStack($patchGIHome) || die(dieformat(117)); clscfgPatch($patchGIHome) || die(dieformat(180, 'clscfg -patch')); stopRollingPatch($patchGIHome) || die(dieformat(431)); # Show cluster active patch level my $CRSCTL = catfile($patchGIHome, 'bin', 'crsctl'); system_cmd($CRSCTL, 'query', 'crs', 'activeversion', '-f'); ($CFG->compACFS)->start() || print_error(426); #actionOKADriversResource("start") || print_error(2009); # Call this before starting mgmtdb if ($CFG->NORESTART) { trace("Re-enable RESOURCE_USE_ENABLED after the rolling patch is finished"); setCRSResourceUseAttr($patchGIHome, 'enable') || die(dieformat(180, 'crsctl set resource use')); } if ((! $CFG->GIMOVE) && (isMgmtdbConfigured())) { # This is the -postpatch case if (isFirstNodeToPatch($patchGIHome)) { trace("Attempt to stop Mgmt DB before disabling it"); srvctl(TRUE, "stop mgmtdb -f", $patchGIHome) || die(dieformat(489)); trace("First node: disable Mgmt DB globally"); srvctl(TRUE, "disable mgmtdb", $patchGIHome) || die(dieformat(491)); my $host = tolower_host(); trace("Enable Mgmt DB on the first node: $host"); srvctl(TRUE, "enable mgmtdb -n $host", $patchGIHome) || die(dieformat(492)); if ($CFG->NORESTART) { trace("Restart the stack to make RESOURCE_USE_ENABLED really enabled"); stopFullStack("force", $patchGIHome) || die(dieformat(349)); startFullStack($patchGIHome) || die(dieformat(117)); } trace("Attempt to start Mgmt DB on the first node: $host"); srvctl(TRUE, "start mgmtdb -n $host", $patchGIHome) || die(dieformat(490)); } else { if (postpatch_isLastNodeToPatch($patchGIHome)) { trace("Last node: enable Mgmt DB globally"); srvctl(TRUE, "enable mgmtdb", $patchGIHome) || die(dieformat(492)); if (!$CFG->ROLLBACK) { modify102Resources() || die(dieformat(226)); } else { trace("'-rollback' option passed. Doing patch rollback."); } } else { if (isRimNode()) { trace("Bypass enabling Mgmt DB on a leaf node"); } else { my $host = tolower_host(); trace("Enable Mgmt DB on middle node: $host"); srvctl(TRUE, "enable mgmtdb -n $host", $patchGIHome) || die(dieformat(492)); } } } # Always run sqlpatch on the node where the mgmtdb is running if (isMgmtdbRunningOnLocalNode($patchGIHome)) { trace("Starting to patch Mgmt DB ..."); my $sqlpatch = catfile($patchGIHome, 'sqlpatch', 'sqlpatch'); my $cmd = "${sqlpatch} -db -MGMTDB"; trace ("Invoking \"${cmd}\""); my $rc = run_as_user($CFG->params('ORACLE_OWNER'), ${cmd}); if (0 == $rc) { trace("Successfully patched Mgmt DB"); } else { trace("Attempt to patch Mgmt DB failed"); die(dieformat(488)); } } } install_xag($patchGIHome); if ($CFG->NORESTART) { trace("Stop Oracle Clusterare because 'norestart' is specified"); stopFullStack("force", $patchGIHome) || die(dieformat(349)); } return SUCCESS; } ################################################################# ## Function to integrate post-patch steps for GI Home ## -postpatch [-nonrolling] [-norestart] [-destcrshome] ################################################################# sub crsPostPatch { trace("Performing the post patching steps...."); $CFG->compOLR(oraClusterwareComp::oraolr->new("OLR")); $CFG->compOCR(oraClusterwareComp::oraocr->new("OCR")); $CFG->compCHM(oraClusterwareComp::orachm->new("CHM")); my $configuredGIHome = s_get_olr_file("crs_home"); if (! $configuredGIHome) { trace("Postpatch for software only home patching..."); my $crsHome = $CFG->params('ORACLE_HOME'); trace("The GI home being patched: [$crsHome]"); # instantiate scripts instantiate_scripts($crsHome); my $kfodOrig = catfile($crsHome, 'crs', 'utl', 'crswrap.sh'); my $kfodFile = catfile($crsHome, 'bin', 'kfod'); my $kfodbinFile = catfile($crsHome, 'bin', 'kfod.bin'); my $oraowner = $CFG->params('ORACLE_OWNER'); my $oraDbaGrp = $CFG->params('ORA_DBA_GROUP'); copy_file($kfodOrig, $kfodFile, $oraowner, $oraDbaGrp) || die(dieformat(105, $kfodOrig, $kfodFile, $!)); s_set_perms ("0755", $kfodFile) || die(dieformat(153, $kfodFile)); s_set_perms ("0755", $kfodbinFile) || die(dieformat(153, $kfodbinFile)); return SUCCESS; } my $patchGIHome = ($CFG->DESTCRSHOME) ? ($CFG->DESTCRSHOME) : $configuredGIHome; my $dstcrshome = $CFG->DESTCRSHOME; trace("Destination CRS home: $dstcrshome"); trace("Configured GI home: $configuredGIHome"); trace("GI Home to be patched: $patchGIHome"); if (($CFG->DESTCRSHOME) && ($patchGIHome eq $configuredGIHome)) { if (isCkptexist("ROOTCRS_POSTPATCH_OOP_REQSTEPS") && isCkptSuccess("ROOTCRS_POSTPATCH_OOP_REQSTEPS")) { trace("It has already switched to GI home being patched"); } else { trace("The destination GI home is same as the configured " ."GI home for out-of-place GI home patching"); print_info(901); exit(0); } } if (! $CFG->GIMOVE) { crsPostPatchCkpts($patchGIHome); } else { resetPostPatchCkpts(); } performPostPatch($configuredGIHome, $patchGIHome); if ((! $CFG->GIMOVE) && (postpatch_isLastNodeToPatch($patchGIHome))) { # reset the status of global ckpt "ROOTCRS_PATCHINFO" on the lastNodeToPatch writeGlobalCkpt("ROOTCRS_PATCHINFO", CKPTSTART, "-transferfile"); } writeCkpt("ROOTCRS_POSTPATCH", CKPTSUC); return SUCCESS; } sub startRollingPatch { my $crshome = shift; my $suc = FALSE; my $CRSCTL = catfile($crshome, 'bin', 'crsctl'); trace("Setting the cluster in rolling patch mode ..."); my @output = system_cmd_capture($CRSCTL, 'start', 'rollingpatch'); my $rc = shift @output; if (0 == $rc) { $suc = TRUE; trace("Successfully set the cluster in rolling patch mode"); } else { if (scalar(grep(/1152/, @output)) > 0) { $suc =TRUE; trace("The cluster is already in rolling patch mode"); } } if(!$suc) { print_lines(@output); } return $suc; } sub stopRollingPatch { my $crshome = shift; my $suc = FALSE; my $CRSCTL = catfile($crshome, 'bin', 'crsctl'); my $oraocr = $CFG->compOCR; trace("Transition the cluster out of rolling patch mode"); my @output = system_cmd_capture($CRSCTL, 'stop', 'rollingpatch'); my $rc = shift @output; if (0 == $rc) { $suc = TRUE; trace("Successfully transition the cluster out of rolling patch mode"); $oraocr->backupOCR(); } else { if (scalar(grep(/1162/, @output)) > 0) { $suc = TRUE; trace("The patch has not been applied on all nodes in the cluster"); } elsif (scalar(grep(/1171/, @output)) > 0) { $suc = TRUE; trace("Distinct patches have been applied on some of nodes"); } elsif (scalar(grep(/1169/, @output)) > 0) { $suc = TRUE; trace("The cluster is consistent and there is no need to " ."transition the cluster out of rolling patch mode"); } } if(!$suc) { print_lines(@output); } return $suc; } sub clscfgLocalPatch { my $crshome = shift; my $suc = FALSE; my $CLSCFG = catfile($crshome, 'bin', 'clscfg'); trace("Patch an existing configuration in OLR"); my @output = system_cmd_capture($CLSCFG, '-localpatch'); my $rc = shift @output; if (0 == $rc) { $suc = TRUE; trace("Successfully patched an existing configuration in OLR"); } return $suc; } sub clscfgPatch { my $crshome = shift; my $suc = FALSE; my $CLSCFG = catfile($crshome, 'bin', 'clscfg'); trace("Patch an existing configuration"); my @output = system_cmd_capture($CLSCFG, '-patch'); my $rc = shift @output; if (0 == $rc) { $suc = TRUE; trace("Successfully patched an existing configuration"); } return $suc; } sub crsPrePatchCkpts { my $destcrshome = ($CFG->DESTCRSHOME) ? ($CFG->DESTCRSHOME) : "null"; my $nonrolling = ($CFG->NONROLLING) ? ($CFG->NONROLLING) : 0; my $norestart = ($CFG->NORESTART) ? ($CFG->NORESTART) : 0; writeCkpt("ROOTCRS_PREPATCH", CKPTSTART); writeCkptProperty("ROOTCRS_PREPATCH", "NONROLLING", $nonrolling); writeCkptProperty("ROOTCRS_PREPATCH", "DESTCRSHOME", $destcrshome); writeCkptProperty("ROOTCRS_PREPATCH", "NORESTART", $norestart); $CFG->wipCkptName("ROOTCRS_PREPATCH"); } sub crsPostPatchCkpts { my $patchGIHome = $_[0]; my $destcrshome = ($CFG->DESTCRSHOME) ? ($CFG->DESTCRSHOME) : "null"; my $nonrolling = ($CFG->NONROLLING) ? ($CFG->NONROLLING) : 0; my $norestart = ($CFG->NORESTART) ? ($CFG->NORESTART) : 0; my $softwarepatch; if (! is_dev_env()) { if ((! isCkptexist("ROOTCRS_PREPATCH")) || (CKPTSUC ne getCkptStatus("ROOTCRS_PREPATCH"))) { die("The post patching cannot be run because the pre patching ". "didn't complete successfully\n"); } my $destcrshome2 = getCkptPropertyValue("ROOTCRS_PREPATCH", "DESTCRSHOME"); my $nonrolling2 = getCkptPropertyValue("ROOTCRS_PREPATCH", "NONROLLING"); if (($destcrshome ne trim($destcrshome2)) || ($nonrolling != trim($nonrolling2))) { die("Improper options were specified for command ". "'rootcrs.pl -postpatch'\n"); } if ((! $nonrolling) && (! ($CFG->DESTCRSHOME))) { $softwarepatch = getCkptPropertyValue("ROOTCRS_PREPATCH", "SOFTWAREPATCH"); my $releasepatch = getReleasePatch($patchGIHome); trace("release patch level: $releasepatch"); trace("software patch level: $softwarepatch"); if ($releasepatch eq trim($softwarepatch)) { # This should not be fatal because we expect the postpatch script to # continue in case there is an issue with applying the patch on the # first node. trace("Oracle Clusterware patch level has not changed after the patch application step"); } } } writeCkpt("ROOTCRS_POSTPATCH", CKPTSTART); writeCkptProperty("ROOTCRS_POSTPATCH", "NONROLLING", $nonrolling); writeCkptProperty("ROOTCRS_POSTPATCH", "NORESTART", $norestart); if ($CFG->DESTCRSHOME) { # The 'NEW_GIHOME/crsctl query crs releasepatch' command # should not be used here for getting the releasepatch # level, because all the paths in the 'crsctl' script still # point to the old home before installPatchedScripts() although # it's invoked from the new home. if (isCkptPropertyExists("ROOTCRS_POSTPATCH", "DESTCRSHOME")) { my $ckptDestCRSHome = getCkptPropertyValue("ROOTCRS_POSTPATCH", "DESTCRSHOME"); $ckptDestCRSHome = trim($ckptDestCRSHome); trace("ckptDestCRSHome: [$ckptDestCRSHome]; destcrshome: [$destcrshome]"); if ($destcrshome ne $ckptDestCRSHome) { trace("Reset checkpoints for patching new CRS home"); resetPostPatchCkpts(); } } else { trace("Reset checkpoints for the first time the '-postpatch' runs for " . "OOP patching"); resetPostPatchCkpts(); } } else { # In-place patching my $releasepatch = getReleasePatch($patchGIHome); if (isCkptPropertyExists("ROOTCRS_POSTPATCH", "RELEASEPATCH")) { my $ckptrelpatch = getCkptPropertyValue("ROOTCRS_POSTPATCH", "RELEASEPATCH"); $ckptrelpatch = trim($ckptrelpatch); trace("ckptrelpatch: [$ckptrelpatch]; releasepatch: [$releasepatch]"); if ($ckptrelpatch != $releasepatch) { trace("Reset checkpoints for separate patch rounds"); resetPostPatchCkpts(); writeCkptProperty("ROOTCRS_POSTPATCH", "RELEASEPATCH", $releasepatch); } } else { trace("Reset checkpoints for the first time the '-postpatch' runs for " . "in-place patching"); resetPostPatchCkpts(); trace("Write current releasepatch level [$releasepatch] into checkpoints"); writeCkptProperty("ROOTCRS_POSTPATCH", "RELEASEPATCH", $releasepatch); } } writeCkptProperty("ROOTCRS_POSTPATCH", "DESTCRSHOME", $destcrshome); $CFG->wipCkptName("ROOTCRS_POSTPATCH"); } sub resetPostPatchCkpts { trace("Reseting checkpoints ..."); if (isCkptexist("ROOTCRS_POSTPATCH_LOCKDSTHOME")) { writeCkpt("ROOTCRS_POSTPATCH_LOCKDSTHOME", CKPTSTART); } if (isCkptexist("ROOTCRS_POSTPATCH_AFDINST")) { writeCkpt("ROOTCRS_POSTPATCH_AFDINST", CKPTSTART); } if (isCkptexist("ROOTCRS_POSTPATCH_ACFSINST")) { writeCkpt("ROOTCRS_POSTPATCH_ACFSINST", CKPTSTART); } #if (isCkptexist("ROOTCRS_POSTPATCH_OKAINST")) #{ # writeCkpt("ROOTCRS_POSTPATCH_OKAINST", CKPTSTART); #} if (isCkptexist("ROOTCRS_POSTPATCH_OOP_PRESTEPS")) { writeCkpt("ROOTCRS_POSTPATCH_OOP_PRESTEPS", CKPTSTART); } if (isCkptexist("ROOTCRS_POSTPATCH_OOP_REQSTEPS")) { writeCkpt("ROOTCRS_POSTPATCH_OOP_REQSTEPS", CKPTSTART); } } # NOTE: this subroutine only works during postpatch, i.e., must call it # after 'crsctl stop rollingpatch'. sub postpatch_isLastNodeToPatch { my $crshome = $_[0]; my $lastNode; if (defined $CFG->isLastNodeToPatch) { $lastNode = $CFG->isLastNodeToPatch; trace("Postpatch: isLastNodeToPatch is $lastNode"); return $lastNode; } my $releasepatch = getReleasePatch($crshome); my $activePatchLevel = getActivePatchLevel($crshome); if ($activePatchLevel eq $releasepatch) { trace("The Clusterware active patch level [$activePatchLevel] has been " . "updated to [$releasepatch]."); $lastNode = TRUE; } else { $lastNode = FALSE; } trace("Postpatch: isLastNode is $lastNode"); $CFG->isLastNodeToPatch($lastNode); return $lastNode; } sub getSoftwarePatch { my $crshome = $_[0]; my $node = $_[1]; my $sftpatch; trace("setting ORAASM_UPGRADE to 1"); $ENV{'ORAASM_UPGRADE'} = "1"; my $nodename = ($node) ? $node: ""; my $CRSCTL = catfile($crshome, 'bin', 'crsctl'); my @output = system_cmd_capture($CRSCTL, 'query', 'crs', 'softwarepatch', $nodename); my $rc = shift @output; if (0 == $rc) { if ($output[0] =~ / \[(.+)\]/) { $sftpatch = $1; } } trace("Oracle Clusterware patch level on node '$nodename' is [$sftpatch]"); return $sftpatch; } sub getReleasePatch { my $crshome = $_[0]; my $relpatch; my $CRSCTL = catfile($crshome, 'bin', 'crsctl'); my @output = system_cmd_capture($CRSCTL, 'query', 'crs', 'releasepatch'); my $rc = shift @output; if (0 == $rc) { if ($output[0] =~ / \[(.+)\].+\[(.*)\]/) { $relpatch = $1; } elsif ($output[0] =~ / \[(.+)\]/) { $relpatch = $1; } } trace("Oracle Clusterware release patch level is [$relpatch]"); return $relpatch; } sub getActivePatchLevel { my $crshome = $_[0]; my $apl; trace("setting ORAASM_UPGRADE to 1"); $ENV{'ORAASM_UPGRADE'} = "1"; my $CRSCTL = catfile($crshome, 'bin', 'crsctl'); my @output = system_cmd_capture($CRSCTL, 'query', 'crs', 'activeversion', '-f'); my $rc = shift @output; if (0 == $rc) { if ($output[0] =~ /\[(.+)\].+\[(.+)\].+\[(.+)\]/) { $apl = $3; } } trace("Oracle Clusterware active patch level is [$apl]"); return $apl; } # This subroutine works during prepatch and postpatch. # If the global checkpoint ROOTCRS_PATCHINFO does not exist or its status is START, # then it is the first node to patch. sub isFirstNodeToPatch { my $crshome = $_[0]; my $globalCkptName = "ROOTCRS_PATCHINFO"; my $globalCkptPrpt_nodeList = "NODENAME_LIST"; my $globalCkptPrpt_firstNode = "FIRSTNODE_TOPATCH"; my $localNode = tolower_host(); if (! isCkptexist($globalCkptName, "-global")) { writeGlobalCkpt($globalCkptName, CKPTSTART); } if (! isCkptSuccess($globalCkptName, "-global")) { trace("First node to patch"); my $isStackUp = checkGIStack($crshome); if ($isStackUp != GI_STACK_UP) { stopFullStack("force", $crshome) || die(dieformat(349)); startCrsWithoutResources($crshome); } my ($rc, @nodeList) = get_olsnodes_info($crshome); if ($rc == 0) { my $nodelist = join(",", @nodeList); # Bug #23279387 and #23094557: NODE_NAME_LIST is not instantiated during # OLFS patching. # This is a temporary fix. The actual fix is to not use crsconfig_params # after install is done. The file is copied to the new home when patching # OLFS homes. Bug 24348626. if ($CFG->params('NODE_NAME_LIST') eq '') { my $paramfile = catfile($crshome, "crs", "install", "crsconfig_params"); modifyparamfile("NODE_NAME_LIST", $nodelist, $paramfile); $CFG->params('NODE_NAME_LIST', $nodelist); } writeCkptProperty($globalCkptName, $globalCkptPrpt_firstNode, $localNode, "-global"); writeCkptProperty($globalCkptName, $globalCkptPrpt_nodeList, $nodelist, "-global"); writeGlobalCkpt($globalCkptName, CKPTSUC, "-transferfile"); } else { writeGlobalCkpt($globalCkptName, CKPTFAIL, "-transferfile"); die(dieformat(174)); } return TRUE; } else { my $firstNode = getCkptPropertyValue($globalCkptName, $globalCkptPrpt_firstNode, "-global"); if ($firstNode eq $localNode) { trace("First node to patch"); return TRUE; } } return FALSE; } # This subroutine only works during prepatch. # Note: this subroutine will return FALSE if used during postpatch # on the last node and after APL has been updated. DO NOT use in postpatch. sub isLastNodeToPatch { my $crshome = $_[0]; my $lastNode; if (defined $CFG->isLastNodeToPatch) { $lastNode = $CFG->isLastNodeToPatch; trace("Prepatch: isLastNodeToPatch is $lastNode"); return $lastNode; } my $host = tolower_host(); my $localNodePatchLevel = getSoftwarePatch($crshome, $host); my $rmtNodePatchLevel = undef; my $globalCkptName = "ROOTCRS_PATCHINFO"; my $globalCkptPrpt_nodeList = "NODENAME_LIST"; my @clunodes; if (isCkptSuccess($globalCkptName, "-global")) { my $nodelist = getCkptPropertyValue($globalCkptName, $globalCkptPrpt_nodeList, "-global"); @clunodes = split(',', $nodelist); } foreach my $node (@clunodes) { if (lc($node) =~ /\b$host\b/i) { next; } my $iNodePatchLevel = getSoftwarePatch($crshome, $node); if ($iNodePatchLevel == $localNodePatchLevel) { trace("The local node has the same software patch". " level [$localNodePatchLevel] as remote node '$node'"); $lastNode = FALSE; } if ((defined($rmtNodePatchLevel)) && ($iNodePatchLevel != $rmtNodePatchLevel)) { trace("The remote node '$node' has different software patch". " level [$iNodePatchLevel] than other remote nodes"); $lastNode = FALSE; } $rmtNodePatchLevel = $iNodePatchLevel; } if (! defined $lastNode) { $lastNode = TRUE; } trace("Prepatch: isLastNodeToPatch is $lastNode"); $CFG->isLastNodeToPatch($lastNode); return $lastNode; } sub prechecksForRollingPatch { my $crshome = $_[0]; my $m_isFirstNodeToPatch = isFirstNodeToPatch($crshome); if ((! skipSharednessCheck()) && $m_isFirstNodeToPatch) { my @activeNodes; my $isStackUp = checkGIStack($crshome); if ($isStackUp != GI_STACK_UP) { stopFullStack("force", $crshome) || die(dieformat(349)); startCrsWithoutResources($crshome); } # Bug#23733697: always enable the resource use at this point setCRSResourceUseAttr($crshome, 'enable') || die(dieformat(180, 'crsctl set resource use')); my %nodeStatus = getNodeStatus($crshome); while (my($key, $value) = each %nodeStatus) { if (1 == $value) { push(@activeNodes, $key); } } if ((! is_dev_env()) && (! ($CFG->DESTCRSHOME)) && (isHomeShared(\@activeNodes))) { trace("Rolling in-place patching is not allowed for a shared GI home"); writeGlobalCkpt("ROOTCRS_PATCHINFO", CKPTSTART, "-transferfile"); die(dieformat(483)); } } if ((isBigCluster())) { if (! isHubNode()) { if ($m_isFirstNodeToPatch) { # reset the status of global ckpt "ROOTCRS_PATCHINFO" writeGlobalCkpt("ROOTCRS_PATCHINFO", CKPTSTART, "-transferfile"); die(dieformat(455)); } } else { if ($m_isFirstNodeToPatch) { if (1 == getActiveNodes($crshome, NODE_ROLE_HUB)) { trace("At least 2 active hub nodes are required to do rolling". " patching."); writeGlobalCkpt("ROOTCRS_PATCHINFO", CKPTSTART, "-transferfile"); die(dieformat(493)); } } } } } # Set the modification time to the current time on the two oc4j files # sub modifyOC4JFiles { my $patchGIHome = $_[0]; my $gridHomeEarFile = catfile ($patchGIHome, 'oc4j', 'j2ee', 'home', 'applications', 'gridhome.ear'); my $dbWlmEarFile = catfile ($patchGIHome, 'oc4j', 'j2ee', 'home', 'applications', 'dbwlm.ear'); # The OC4J container needs the modification time on the file to be changed in order to # unpack the jar files when the container is started (bug 19602208) # The opatch apply does not change the modification time when the patch is applied. my $now = time(); if (-e $gridHomeEarFile) { trace("Setting the modification time on file $gridHomeEarFile"); if (!utime($now, $now, $gridHomeEarFile)) { trace("Failed to set the modification time on file $gridHomeEarFile"); die(dieformat(900, $gridHomeEarFile, $!)); } } if (-e $dbWlmEarFile) { trace("Setting the modification time on file $dbWlmEarFile"); if (!utime($now, $now, $dbWlmEarFile)) { trace("Failed to set the modification time on file $dbWlmEarFile"); die(dieformat(900, $dbWlmEarFile, $!)); } } } # Function: get the Software Patch Level from OLR. # The function can be called when stack is not up as root user. # Args : [0] Crs home # Returns : Software Patch Level (OLR) of the current node sub getSoftwarePatchOLR { my $crshome = $_[0]; my $sftpatch; my $CRSCTL = catfile($crshome, 'bin', 'crsctl'); my @output = system_cmd_capture($CRSCTL, 'query', 'crs', 'softwarepatch', '-l'); my $rc = shift @output; if (0 == $rc) { if ($output[0] =~ / \[(.+)\]/) { $sftpatch = $1; } } trace("Software Patch Level on local node is [$sftpatch]"); return $sftpatch; } 1;