Twitter

Showing posts with label opatch. Show all posts
Showing posts with label opatch. Show all posts

Grid Infrastructure Out of Place Patching (aka GI OOP)

Out of Place patching has become the standard for database patching for years now (I have described it precisely here) but for any reason, people restrain themselves for doing Out of Place patching for Grid Infrastructure and usually do In Place GI patching and Out of Place GI upgrade (you cannot do In Place upgrade :)). I will describe below how to easily perform GI OOP.

To start on the right foot, a quick reminder of the concept and the required steps of an Out of Place patching:
  1. Your system is running on a source version home let's say /u01/app/19.0.0.0/grid
  2. You prepare the future alread patched target home let's say /u01/app/19.11.0.0/grid
  3. The day of the maintenance, you stop what is running on the source home and restart on the target home
  4. If, for any reason, something goes wrong, you just have to restart everything on the source home
This can be represented with the below image:






For the purpose of this blog, I will use the below homes in the examples:
  • The source GI home: /u01/app/19.0.0.0/grid
  • The target GI Home: /u01/app/19.11.0.0/grid

1. Prepare your target home

Preparing the target home is to prepare a GI home with the patches you will want to use; here, I will go with GI 19.11 with the latest opatch, the latest GI JDK and patch 31602782. To achieve this, you can clone a source GI Home or, what I prefer and recommend, to create a gold image of your target home. Oracle has/had a note with a list of already prepared gold image per version but this note has kind of disappeared recently so I gave up on that one. Also, building your own gold image is easy and very good to know how all of that works. To build my target GI 19.11 gold image, you first need to get:
  • The base GI 19c version which is 19.3: GI_gold_193_V982068-01.zip -- from edelivery.oracle.com
  • The GI 19.11 patch: GI_1911_p32545008_190000_Linux-x86-64.zip
  • The latest opatch: opatch_p6880880_122010_Linux-x86-64.zip
  • The latest GIJDK: GIJDK_April2021_p32490416_190000_Linux-x86-64.zip (this one is no more the latest but it was the latest when I did this gold image)
  • The patch 31602782: p31602782_1911000DBRU_Linux-x86-64.zip
Note: you may want to have a look at this blog to get the notes where to download GI, the critical patches, GI JDK, etc... Note 2: you do not have to apply the latest GI JDK, it is to show that you can apply any one-off patch on top of the RUR in your target gold image -- GI tends to have many critical issues and then patches so better to be know how to deal with it. Here is what it looks like once you have the files on your server:
[root@target gioop]# pwd
/u01/stage/gioop
[root@target gioop]# ls -ltr
GI_1911_p32545008_190000_Linux-x86-64.zip               <= GI 19.11 patch
GIJDK_April2021_p32490416_190000_Linux-x86-64.zip       <= April JDK
opatch_p6880880_122010_Linux-x86-64.zip                 <= Latest opatch
GI_gold_193_V982068-01.zip                              <= GI gold image
p31602782_1911000DBRU_Linux-x86-64.zip                  <= Patch 31602782
[root@target gioop]#
Unzip the 19.3 gold image:
[root@target gioop]# mkdir temp
[root@target gioop]# unzip -q GI_gold_193_V982068-01.zip -d temp/.
[root@target gioop]#
Unzip the GI JDK and the 31602782 patch (any number of one-off patches):
[root@target gioop]# unzip -o -q GIJDK_April2021_p32490416_190000_Linux-x86-64.zip
[root@target gioop]# unzip -o -q p31602782_1911000DBRU_Linux-x86-64.zip
[root@target gioop]#
Very importantly, all needs to be done as the oracle (grid owner) user (not root) so give the correct permissions and you should have the below situation:
[root@target gioop]# chown -R oracle:oinstall /u01/stage/gioop
[root@target gioop]# ls -ltr
oracle oinstall       4096 Apr 20 07:17 32545008                                           <= GI 19.11 patch
oracle oinstall       2477 Apr 22 16:16 PatchSearch.xml
oracle oinstall 2523672126 May  7 11:28 GI_1911_p32545008_190000_Linux-x86-64.zip
oracle oinstall  125203135 May  7 11:28 GIJDK_April2021_p32490416_190000_Linux-x86-64.zip
oracle oinstall  120761121 May  7 11:28 opatch_p6880880_122010_Linux-x86-64.zip
oracle oinstall 2889184573 May  7 12:26 GI_gold_193_V982068-01.zip
oracle oinstall       4096 May  7 12:28 temp                                               <= GI gold image 
oracle oinstall       4096 May  7 12:33 32490416                                           <= GI JDK
oracle oinstall       4096 Apr 25 21:04 31602782                                           <= Patch 31602782
[root@target gioop]#
Start by upgrading opatch to the latest version:
[root@target gioop]# su - oracle
[oracle@target:]/home/oracle => cd /u01/stage/gioop/temp
[oracle@target:]/u01/stage/gioop/temp => ./OPatch/opatch version
OPatch Version: 12.2.0.1.17
OPatch succeeded.
[oracle@target:]/u01/stage/gioop/temp => unzip -o -q ../opatch_p6880880_122010_Linux-x86-64.zip
[oracle@target:]/u01/stage/gioop/temp =>./OPatch/opatch version
OPatch Version: 12.2.0.1.24
OPatch succeeded.
[oracle@target:]/u01/stage/gioop/temp =>
We can now patch the gold image with GI 19.11, the GI JDK and the patch 31602782; we can do all of this in a single command line:
[oracle@target:]/u01/stage/gioop/temp => ./gridSetup.sh -silent -printtime -waitForCompletion -noCopy -applyRU /u01/stage/gioop/32545008 -applyOneOffs /u01/stage/gioop/31602782,/u01/stage/gioop/32490416
Preparing the home to patch...
Applying the patch /u01/stage/gioop/32545008...
Successfully applied the patch.
Applying the patch /u01/stage/gioop/31602782...
Successfully applied the patch.
Applying the patch /u01/stage/gioop/32490416...
Successfully applied the patch.
The log can be found at: /u01/app/oraInventory/logs/GridSetupActions2021-05-07_01-12-59PM/installerPatchActions_2021-05-07_01-12-59PM.log
Launching Oracle Grid Infrastructure Setup Wizard...
[FATAL] [INS-40426] Grid installation option has not been specified.       <== you can ignore this error
   ACTION: Specify the valid installation option.
[oracle@target:]/u01/stage/gioop/temp =>
Before continuing, we need to temporarely attach the home to the system:
[oracle@target:]/home/oracle => /u01/app/19.0.0.0/grid/oui/bin/runInstaller -attachHome ORACLE_HOME=/u01/stage/gioop/temp ORACLE_HOME_NAME=gold_gi1911
Starting Oracle Universal Installer...

Checking swap space: must be greater than 500 MB.   Actual 24575 MB    Passed
The inventory pointer is located at /etc/oraInst.loc
You can find the log of this install session at:
 /u01/app/oraInventory/logs/AttachHome2021-05-07_01-53-14PM.log
'AttachHome' was successful.
[oracle@target:]/home/oracle =>
Note that you have to attach the home to be able to use opatch and create a gold image but you cannot apply the RU nor the one-off patches if the home is attached:
[oracle@target:]/u01/stage/gioop/temp => ./gridSetup.sh -silent -printtime -waitForCompletion -noCopy -applyRU /u01/stage/gioop/32545008 -applyOneOffs /u01/stage/gioop/31602782,/u01/stage/gioop/32490416
[INS-32826] The software home (/u01/stage/gioop/temp) is already registered in the central inventory. Refer to patch readme instructions on how to apply.
[oracle@target:]/u01/stage/gioop/temp =>
We now have a prepared target home with our target version located in a temporary directory. We can verify the list of patch of our home:
[oracle@target:]/u01/stage/gioop/temp => ./OPatch/opatch lspatches -oh /u01/stage/gioop/temp
31602782;SAME INSTANCE SLAVE PARSE FAILURE FLOOD CONTROL
32490416;JDK BUNDLE PATCH 19.0.0.0.210420
32585572;DBWLM RELEASE UPDATE 19.0.0.0.0 (32585572)
32584670;TOMCAT RELEASE UPDATE 19.0.0.0.0 (32584670)
32579761;OCW RELEASE UPDATE 19.11.0.0.0 (32579761)
32576499;ACFS RELEASE UPDATE 19.11.0.0.0 (32576499)
32545013;Database Release Update : 19.11.0.0.210420 (32545013)

OPatch succeeded.
[oracle@target:]/u01/stage/gioop/temp =>
We will now create our own gold image which we could easily copy and deploy on all the other systems (dev, qa, dr, prod, etc ...):
[oracle@target:]/u01/stage/gioop/temp =>  ./gridSetup.sh -silent -createGoldImage -destinationLocation /u01/stage/gioop/
Launching Oracle Grid Infrastructure Setup Wizard...
Successfully Setup Software.
Gold Image location: /u01/stage/gioop/grid_home_2021-05-07_01-59-02PM.zip
[oracle@target:]/u01/stage/gioop/temp =>
You can now save the prepared gold image /u01/stage/gioop/grid_home_2021-05-07_01-59-02PM.zip on a central repository server as this is the image you will be usng on all your systems -- this is your future GI !

To keep your systems clean, let's detach the temporary home:
[oracle@target:]/u01/stage/gioop/temp => /u01/app/19.0.0.0/grid/oui/bin/runInstaller -detachHome ORACLE_HOME=/u01/stage/gioop/temp ORACLE_HOME_NAME=gold_gi1911
Starting Oracle Universal Installer...

Checking swap space: must be greater than 500 MB.   Actual 24575 MB    Passed
The inventory pointer is located at /etc/oraInst.loc
[oracle@target:]/u01/stage/gioop/temp =>


2.Switch the home

Create the target GI directory on all the servers
[root@exadb01 ~]# cat ~/dbs_group
exadb01
exadb02
. . .
exadb08
[root@exadb01 ~]# dcli -g ~/dbs_group -l root "df -h /u01"
Filesystem                    Size  Used Avail Use% Mounted on
exad01: /dev/mapper/VGExaDb-LVDbOra1  250G  125G  125G  50% /u01          <= check that you have enough disk space on each node
. . .
[root@exadb01 ~]# dcli -g ~/dbs_group -l root "mkdir -p /u01/app/19.11.0.0/grid; chown -R oracle:oinstall /u01/app/19.11.0.0/grid"
[root@exadb01 ~]# 
Unzip the previously prepared goldimage (only on one node !)
[oracle@exadb01:]/home/oracle => unzip -q /u01/stage/gioop/GI_gold_1911_2021-05-07_01-59-02PM.zip -d /u01/app/19.11.0.0/grid
[oracle@exadb01:]/home/oracle => dcli -g ~/dbs_group -l oracle "du -sh /u01/app/19.11.0.0/grid"
exadb01: 9.9G      /u01/app/19.11.0.0/grid      <== your gold image unzipped here 
exadb02: 4.0K      /u01/app/19.11.0.0/grid      <== empty directory here
. . .
exadb08: 4.0K      /u01/app/19.11.0.0/grid<     <== empty directory here
[oracle@exadb01:]/home/oracle =>
Something important here to aboid issues during the patch process; verify that the ASM passwordfile and the ASM spfile is located under ASM (if not, you'll find a quick procedure here on how to move them to ASM):
[root@exadb01 ~]# . oraenv <<< +ASM1
ORACLE_SID = [root] ? The Oracle base has been set to /u01/app/oracle
[root@exadb01 ~]# asmcmd spget
+DATA/mycluster/ASMPARAMETERFILE/registry.253.1045914043
[root@exadb01 ~]# asmcmd pwget --asm
+DATA/orapwASM
[root@exadb01 ~]#
Prepare a responsefile such as this one:
[oracle@exadb01:+ASM1]/home/oracle => cat /u01/stage/gioop/1911oop_response.rsp
oracle.install.responseFileVersion=/oracle/install/rspfmt_crsinstall_response_schema_v19.0.0
oracle.install.option=CRS_SWONLY
ORACLE_BASE=/u01/app/oracle
oracle.install.asm.OSDBA=oinstall
oracle.install.asm.OSOPER=oinstall
oracle.install.asm.OSASM=oinstall
oracle.install.crs.config.ClusterConfiguration=STANDALONE
[oracle@exadb01:+ASM1]/home/oracle =>
Gridsetup, this will only copy the software across all the nodes, this will NOT modify anything else
[oracle@exadb01:]/u01/app/19.11.0.0/grid => ./gridSetup.sh -silent -responseFile /u01/stage/gioop/1911oop_response.rsp -waitForCompletion
Launching Oracle Grid Infrastructure Setup Wizard...

[WARNING] [INS-41813] OSDBA for ASM, OSOPER for ASM, and OSASM are the same OS group.
   CAUSE: The group you selected for granting the OSDBA for ASM group for database access, and the OSOPER for ASM group for startup and shutdown of Oracle ASM, is the same group as the OSASM group, whose members have SYSASM privileges on Oracle ASM.
   ACTION: Choose different groups as the OSASM, OSDBA for ASM, and OSOPER for ASM groups.
[WARNING] [INS-41874] Oracle ASM Administrator (OSASM) Group specified is same as the inventory group.
   CAUSE: Operating system group oinstall specified for OSASM Group is same as the inventory group.
   ACTION: It is not recommended to have OSASM group same as inventory group. Select any of the group other than the inventory group to avoid incorrect configuration.
The response file for this session can be found at:
 /u01/app/19.11.0.0/grid/install/response/grid_2021-05-10_10-54-29AM.rsp

You can find the log of this install session at:
 /u01/app/oraInventory/logs/GridSetupActions2021-05-10_10-54-29AM/gridSetupActions2021-05-10_10-54-29AM.log

As a root user, execute the following script(s):
        1. /u01/app/19.11.0.0/grid/root.sh

Execute /u01/app/19.11.0.0/grid/root.sh on the following nodes:
[exadb01]
As instructed, run this root.sh script:
[root@exadb01 ~]# /u01/app/19.11.0.0/grid/root.sh
Check /u01/app/19.11.0.0/grid/install/root_exadb01.domain.com_2021-05-10_11-03-09-927603750.log for the output of root script
[root@exadb01 ~]# cat /u01/app/19.11.0.0/grid/install/root_exadb01.domain.com_2021-05-10_11-03-09-927603750.log
Performing root user operation.

The following environment variables are set as:
    ORACLE_OWNER= oracle
    ORACLE_HOME=  /u01/app/19.11.0.0/grid
   Copying dbhome to /usr/local/bin ...
   Copying oraenv to /usr/local/bin ...
   Copying coraenv to /usr/local/bin ...

Entries will be added to the /etc/oratab file as needed by
Database Configuration Assistant when a database is created
Finished running generic part of root script.
Now product-specific root actions will be performed.

To configure Grid Infrastructure for a Cluster or Grid Infrastructure for a Stand-Alone Server execute the following command as oracle user:
/u01/app/19.11.0.0/grid/gridSetup.sh
This command launches the Grid Infrastructure Setup Wizard. The wizard also supports silent operation, and the parameters can be passed through the response file that is available in the installation media.

[root@exadb01 ~]#
OK, this was the last step to be done before the real maintenance, the next steps are do be done under a window maintenance only as the GI will be switched to the new home node by node stopping all the resources running on the old GI home and restarting all the resources on the new GI home. I will recommend using the rac-status.sh script to check the status of all the resources of the cluster before switching the home -- and do the same after the home switching to ensure that your maintenance is idempotent:
[oracle@exadb01:]/home/oracle => /u01/app/19.11.0.0/grid/gridSetup.sh -silent -switchGridHome
Launching Oracle Grid Infrastructure Setup Wizard...

You can find the log of this install session at:
 /u01/app/oraInventory/logs/cloneActions2021-05-10_11-05-43AM.log

As a root user, execute the following script(s):
        1. /u01/app/19.11.0.0/grid/root.sh

Execute /u01/app/19.11.0.0/grid/root.sh on the following nodes:
[exadb01, exadb02, exadb03, exadb04, exadb05, exadb06, exadb07, exadb08]

Run the scripts on the local node first. After successful completion, run the scripts in sequence on all other nodes.

Successfully Setup Software.
[oracle@exadb01:]/home/oracle =>
Now, strictly follow the instructions and run the root.sh scripts as instructed; do NOT run them concurrently on multiple nodes; note that they will take time to run:
[root@exadb01 ~]# /u01/app/19.11.0.0/grid/root.sh
Check /u01/app/19.11.0.0/grid/install/root_exadb01.domain.com_2021-05-10_11-11-21-158300990.log for the output of root script
[root@exadb01 ~]#
And so on on all the nodes one by one ... and you are done ! hmm not exactly you need to update your /etc/oratab (on each node) as the ASM entry will be removed by the patching:
[root@exadb01 ~]# grep ASM /etc/oratab
+ASM1:/u01/app/19.11.0.0/grid:N
You can have a look at the inventory and you could see the old and new GI Home as below:
[root@exadb01 ~]# dcli -g ~/dbs_group -l root "grep -i grid /u01/app/oraInventory/ContentsXML/inventory.xml"
exadb01: <HOME NAME="OraGI19Home1" LOC="/u01/app/19.0.0.0/grid" TYPE="O" IDX="1">                     <== old
exadb01: <HOME NAME="OraGI19Home2" LOC="/u01/app/19.11.0.0/grid" TYPE="O" IDX="19" CRS="true"/>       <== new
. . .
exadb08: <HOME NAME="OraGI19Home1" LOC="/u01/app/19.0.0.0/grid" TYPE="O" IDX="1">                     <== old
exadb08: <HOME NAME="OraGI19Home2" LOC="/u01/app/19.11.0.0/grid" TYPE="O" IDX="14" CRS="true"/>       <== new
[root@exadb01 ~]#
Now you are all done ! a last check with rac-status.sh to ensure that everything is running as expected and you can use the same gold image and procedure to all your GIs !

3. The Rollback procedure

In case of something goes wrong during or after you have switched to your new home, you need to have a tested rollback procedure and the beauty of Out of Place patching is that the old home is still on the system, untouched, as it was before. You then just have to switch back to the old home.
Note that the below chown -R oracle:oinstall (or to the grid owner) is mandatory; indeed, the switch is ran as root and root.sh will later on put the correct privileges back in place.
[root@exadb01 ~]# dcli -g ~/dbs_group -l root "chown -R oracle:oinstall /u01/app/19.0.0.0/grid"           <== this is mandatory
[root@exadb01 ~]# su - oracle
[oracle@exadb01:]/home/oracle => /u01/app/19.0.0.0/grid/gridSetup.sh -silent -switchGridHome
Launching Oracle Grid Infrastructure Setup Wizard...

You can find the log of this install session at:
 /u01/app/oraInventory/logs/cloneActions2021-05-10_12-25-25PM.log

As a root user, execute the following script(s):
        1. /u01/app/19.0.0.0/grid/root.sh

Execute /u01/app/19.0.0.0/grid/root.sh on the following nodes:
[exadb01, exadb02, exadb03, exadb04, exadb05, exadb06, exadb07, exadb08]

Run the scripts on the local node first. After successful completion, run the scripts in sequence on all other nodes.

Successfully Setup Software.
[oracle@exadb01:]/home/oracle =>
Same as before, now run the root.sh script on each node one by one, do not run them concurrently.
[root@exadb01 ~]# /u01/app/19.0.0.0/grid/root.sh
Check /u01/app/19.0.0.0/grid/install/root_exadb01.domain.com_2021-05-10_12-36-17-716165992.log for the output of root script
[root@exadb01 ~]#
. . .
[root@exadb01 ~]# ssh exadb08
Last login: Mon May 10 11:44:34 2021 from exadb01.domain.com
[root@exadb08 ~]# /u01/app/19.0.0.0/grid/root.sh
Check /u01/app/19.0.0.0/grid/install/root_exadb08.domain.com_2021-05-10_12-49-56-584075655.log for the output of root script
[root@exadb08 ~]#
No, refix back your oratab, execute rac-status.sh to check that everything is back up and running as expected and you are all done !

list-ohpatches.sh: a better Oracle patch reporting tool

Tired of struggling with Oracle patches, I developped lspatches.sh three years ago and I based it on a new feature at that time which was implemented after the opatch -all_nodes option was deprecated; this new feature was a new report -remote option to opatchauto. I must confess that I like new things and this is why I decided to go this new feature instead of basing lspatches.sh on that good old buddy opatch lspatches.

Three years later, I can clearly say that it was a bad decision; indeed many people (and I) had issues mainly because:
  • Oracle clearly dropped the 11g support with this -- but people still have tons of 11g (which may not be a bad idea :))
  • This opatchauto -remote option had many issues just not working properly
  • This option has even been removed and replaced by a -host
Even if this is kind of usual with oracle and the new features, at the end of the day, lspatches.sh was most likely not to work due to the points discussed above.

So I restarted from scratch and developped a new list-ohpatches.sh script based on opatch lspatches which is working forever and also has the advantage of showing the description of the patches which is always good to have. The script is now more reliable, works perfectly with 11g, less code, more simple... in short: better.

How that works ?

list-ohpatches.sh checks the homes from /etc/oratab, runs opatch lspatches on all the nodes of a cluster and makes a nice table, one column by node, showing a green x if the patch is installed on that specific node and a red Missing if a patch is missing as you can see below:
You can then very easily find a missing or extra patch installed on one or many nodes. You can also note that the return code of the script is the number of missing patches so if used by an automatic script, you can easily know if all is good (return code 0) or not OK (return code > 0) and even the number of missing patches.

Below a successful output:

Is it Exadata specific ?

No, it works on any RAC, even on standalone systems.

Is it working for GI and databases Homes ?

Yes, it does work for GI and databases Homes.

Which user to execute the script with ?

opatch lspatches must be run by oracle (not root) so if you run it as root, the script will execute the opatch lspatches commands as oracle (or anothger user if the --oracleuser option is used to specify another "oracle" user) so you can use root or oracle, the script will manage automatically.

Some options

Feel free to check the help of the script (list-ohpatches.sh -h or list-ohpatches.sh --help) for the possible options; it is pretty simple and self-exaplanatory:
# ./list-ohpatches.sh --help

NAME
        list-ohpatches.sh - Show nice tables of the installed and/or missing patches for some GI/DB Oracle Homes

SYNOPSIS
        ./list-ohpatches.sh [-g] [-c] [-G] [-v] [-s] [-u] [-h]

DESCRIPTION
        list-ohpatches.sh Based on oratab, show nice tables of the installed and/or missing patches for some GI/DB Oracle Homes
                       You can then quickly find a missing patch across a RAC system
        list-ohpatches.sh will by default check all the nodes of a cluster (based on olsnodes) which requires ASM to be running
                       and oraenv to be working with the ASM aslias defined in oratab; If you have no ASM alias in oratab,
                       you may suffer from https://unknowndba.blogspot.com/2019/01/lost-entries-in-oratab-after-gi-122.html
                       You can specify a comma separated list of host or a file containing one host per line
        list-ohpatches.sh by default checks all the homes defined in oratab, you can use --grep/--home and --ungrep/--ignore to limit your home selection (see examples below)
        list-ohpatches.sh relies on opatch lspatches which must run as oracle user (and not root); if the script is started as root,
                       the opatch lspatches commands will be run after su - oracle (see -u | --oracleuser for more on this)


OPTIONS
        -g | --groupfile            ) A group file containing a list of hosts
        -c | --commalist  | --hosts ) A comma separated list of hosts
        -G | --grep | --oh | --home ) Pattern to grep from /etc/oratab
        -v | --ungrep | --ignore    ) Pattern to grep -v (ignore) from /etc/oratab
        -s | --showhomes | --show   ) Just show the homes from oratab resolving the grep/ungrep combinations
        -u | --oracleuser           ) User to use to run opatch lspatches if the script is started as root, default is oracle
        -h | --help                 ) Shows this help


EXAMPLES
       ./list-ohpatches.sh                                                       # Analyze and show all the homes of nodes of a cluster
       ./list-ohpatches.sh --show                                                # Show the homes from oratab (only show, dont do anything else)
       ./list-ohpatches.sh --grep grid                                           # Analyze the grid home
       ./list-ohpatches.sh --grep db --ungrep 12                                 # Only the DB homes but not the 12 ones
       ./list-ohpatches.sh --grep db --ungrep 12 --groupfile ~/dbs_group         # Same as above on the hosts contained in the ~/dbs_group file
       ./list-ohpatches.sh --home db --ignore 12 --hosts exa01,exa06             # Same as above but only on hosts exa02 and exa06
       ./list-ohpatches.sh --home db --ignore 12 --hosts exa01,exa06 -u oracle2  # Same as above but started as root; will then su - oracle2 automatically
# 


We now finally have a robust script to show the installed patches across many nodes, enjoy ! You can freely download the script here.

lspatches.sh : an Oracle patch reporting tool

Edit May 24th 2021: this script is now deprecated, you may want to use the more robust list-ohpatches.sh.

Like any other product, Oracle database, ClusterWare (RAC, GI, CRS whatever you name it), ASM, . . . require patches for updates, bug fixing or security purpose and no one would argue that it is not fairly easy to use opatch to apply them.

But opatch's reporting option has room for improvement.

Oh yes for sure there is an opatch lspatches option
[oracle@anexadata_db01 ~]$ $ORACLE_HOME/OPatch/opatch lspatches
27475603;Database PSU 12.1.0.2.180417, Oracle JavaVM Component (APR2018)
21923026;
27338020;OCW PATCH SET UPDATE 12.1.0.2.180417 (27338020)
27338029;Database Bundle Patch : 12.1.0.2.180417 (27338029)
OPatch succeeded.
[oracle@anexadata_db01 ~]$

but this option is not able to provide the patches installed on the remote nodes in case of RAC environment.
Then yes there is the lsinventory -all_nodes option to achieve this (at least for now) :
[oracle@anexadata_db01 ~]$ $ORACLE_HOME/OPatch/opatch lsinventory -all_nodes | wc -l
472
[oracle@anexadata_db01 ~]$

In this example, opatch lsinventory -all_nodes provides with 472 lines for 1 Home over 2 nodes (this has been taken on an Exadata 1/4 RAC) so we could expect getting around 1000 lines with a 4 nodes RAC and then around 2000 lines for a 8 nodes RAC for a single Home (and may be more depending on the number of patches installed). And you may have a dozen of Homes installed so a dozen times more lines to find in the answer of the really important questions any DBA has to answer :
  • Is the patch 123456 well installed on all the nodes ?
  • Is there a missing patch on a Home ?


As a DBA, I already spent hours in these opatch outputs, grepping, copying and pasting information to double check that a patch was well installed on all the homes of a system , etc . . . I spent so much time in these non-added value tasks that something had to changed and I then wrote lspatches.sh ! And my first screenshot will show a missing patch on a Home I found when testing this script ! (despite all the efforts we made to check, this one was missed):


Then here you can easily see that patch 17974457 is missing on Node 2, 3 and 4 !


How that works ?

Basically lspatches.sh will do a lsinvenrory (-all_nodes if RAC), anaylze the output and show if a patch is Missing somewhere. Please have a look at the below example taken on a full Exadata rack.

Note : this output has been truncated to the 2 first Homes for visibility.


Grep only the Homes you want

As you may not want to check the patches on every Home every time, you can choose one or few Homes using the -g and/or the -v option which act as a grep and as a grep -v. Let me show some examples :

# To analyze only the /u01/app/oracle/product/12.1.0.2/dbhome_1 Home :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -g /u01/app/oracle/product/12.1.0.2/dbhome_1

# To analyze the Homes that contain "12" (ie. the 12c Homes) :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -g 12

# To analyze the Homes that contain "12" but that do not contain "oap" :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -g 12 -v oap

# To analyze the "dbhome_2 "Homes but not the 12c ones :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -g dbhome_2 -v 12


Show before proceeding

Unsure about the result of your -g and -v combination ? use the -s option to just show what Homes would be considered before proceeding :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -g 12 -s
ORACLE_HOMEs that would be considered (/etc/oratab) :
        /u01/app/12.1.0.2/grid
        /u01/app/oracle/product/12.1.0.2/dbhome_1
        /u01/app/oracle/product/12.1.0.2/dbhome_2
        /u01/oapdb/12.1.0.2
[oracle@anexadata_db01 ~]$ ./lspatches.sh -g 12 -v oap -s
ORACLE_HOMEs that would be considered (/etc/oratab) :
        /u01/app/12.1.0.2/grid
        /u01/app/oracle/product/12.1.0.2/dbhome_1
        /u01/app/oracle/product/12.1.0.2/dbhome_2
[oracle@anexadata_db01 ~]$ 


And ultimately you can also use the -s option with no other argument just to show the Homes that are installed on you system :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -s
ORACLE_HOMEs that would be considered (/etc/oratab) :
        /u01/app/12.1.0.2/grid
        /u01/app/oracle/product/11.2.0.4/dbhome_1
        /u01/app/oracle/product/11.2.0.4/dbhome_2
        /u01/app/oracle/product/12.1.0.2/dbhome_1
        /u01/app/oracle/product/12.1.0.2/dbhome_2
        /u01/oapdb/12.1.0.2
[oracle@anexadata_db01 ~]$ 


Input and output files are supported

Have you noticed the (/etc/oratab) in the above outputs ? This is because we can also use pre generated opatch outputs files with the -f option as well as just generating an opatch output with -o ! (and also for the Solaris users where oratab is not located in /etc -- more on that later). Please have a look at the below example :
# Generate an opatch output for the 12c Homes
# but not the "oap" ones as I do not want to deal with the EBS DBAs :)

[oracle@anexadata_db01 ~]$  ./lspatches.sh -g 12 -v oap -o opatch_output
Proceeding with /u01/app/12.1.0.2/grid . . .                                            OK
Proceeding with /u01/app/oracle/product/12.1.0.2/dbhome_1 . . .                         OK
Proceeding with /u01/app/oracle/product/12.1.0.2/dbhome_dr2 . . .                       OK

[oracle@anexadata_db01 ~]$ ls -ltr opatch_output
-rw-r--r-- 1 oracle oinstall 578261 Jul  6 00:06 opatch_output

[oracle@anexadata_db01 ~]$ wc -l opatch_output
8139 opatch_output           # 3 Homes across 8 nodes is indeed a lot of lines

[oracle@anexadata_db01 ~]$ 


And now let's use this file as an input for the lspatches.sh script to see for which Homes we have some patch information in :
[oracle@anexadata_db01 ~]$ ./lspatches.sh -f opatch_output -s
ORACLE_HOMEs that would be considered (opatch_output) :
         /u01/app/12.1.0.2/grid
         /u01/app/oracle/product/12.1.0.2/dbhome_1
         /u01/app/oracle/product/12.1.0.2/dbhome_dr2
[oracle@anexadata_db01 ~]$ 


And then analyze this file (without the grid Home) :


 
Few things are interesting in the above screenshot:
  • The /u01/app/oracle/product/12.1.0.2/dbhome_2 Home is only installed on 4 nodes (when this happens the script only shows the nodes where the Home is installed)
  • You can see that there're some Missing patches (I manually modified the input file before taking the screenshot)


Local and remote

As one may not have a RAC installation, the script with start a local opatch session (with no -all_nodes) if the olsnodes command is not here or returns 0 row then you do not have to worry about, lspatches.sh will take care of this for you.

In the case of a RAC configuration, you may not want the remote patches information so you may want to use the -l option to just start a local patch reporting (you can also use the -g and the -v options to grep or ungrep the Homes you want or doesn't want to analyze)
[oracle@anexadata_db01 ~]$ ./lspatches.sh -l

[oracle@anexadata_db01 ~]$ ./lspatches.sh -l -g 12 -v grid


opatchauto report from opatch 12.2.0.1.13 / 11.2.0.3.18

As I wrote about in the past, starting from versions 12.2.0.1.13 and 11.2.0.3.18, opatch does not provide any remote patch information any more meaning the -all_nodes option is discontinued and we now have to use opatchauto report to have such information.
lspatches.sh manages this by itself, using opatchauto report instead of opatch lsinventory -all_nodes if the opatch versions are > 12.2.0.1.13 or > 11.2.0.3.18 for opatch 11g. It is almost transparent for you.
"Almost" transparent ? yes, almost. Indeed, opatch lsinventory only reports the latest installed base patches whereas opatchauto report shows all the installed patches and subpatches. In the below example, opatch lsinventory would only show the most current Bundle patch whereas opatchauto report will also show the previous database Bundle patches.
patch id="27338029" isSqlpatch="true" unique_patch_id="22055339"    --- this is the most current Database Bundle Patch that is installed 

the following are the "sub-patches, i.e. the previous bundle patch versions": 
patch id="26925263" isSqlpatch="true" unique_patch_id="21857460"    --- DATABASE BUNDLE PATCH 12.1.0.2.180116 
patch id="26717470" isSqlpatch="true" unique_patch_id="21611145"    --- DATABASE BUNDLE PATCH 12.1.0.2.171017 
patch id="26609798" isSqlpatch="true" unique_patch_id="21481992"    --- DATABASE BUNDLE PATCH 12.1.0.2.180116 


Non Linux support

I develop and test my scripts on Linux because 99% of my clients are running Linux and sometimes they may not work under other OS specially Solaris. For this one, I really tried hard to accommodate Solaris with /etc/oratab, awk, etc . . . it may not be perfect as I just found an old Solaris 10 to test but it should not be bad. Let me know Solaris users if I missed something here !

-h for help

As lspatches.sh has quite a few options, you may want to use the -h one to show a summary of all the options with some examples.
[oracle@anexadata_db01 ~]$ ./lspatches.sh -h

opatchauto report limitations

As of now, it seems that the below opatchauto report limitations are:
  • It does not provide a description of a base patch like DATABASE BUNDLE PATCH 12.1.0.2.180116
  • There is no option to behave like opatch lsinventory meaning to only show the latest base patch installed and not show all the subpatches
I'll keep an eye on it and update lspatches.sh if Oracle releases such option in a near future.


Thanks for reading, you can download lspatches.sh here, I hope you'll be enjoying this script as much as I enjoy using it on a daily basis !

Exadata : How to Quickly Upgrade opatch with dcli

Before you patch anything, you always have to upgrade the tool that we use to patch : opatch by downloading the last opatch version in the well known patch 6880880. Then you will upgrade opatch on every node of a cluster (up to 8 on Exadata) for every ORACLE_HOME you want to patch.
Hopefully, Exadata comes out with a powerful tool named dcli (you will find the dcli detailed syntax here) which can really ease your Exadata DBA ("DMA" like they call it) life.

I will be showing here how to quickly upgrade opatch with dcli. This example has been performed on a full rack -- then 8 nodes. I'll be presenting here a 12c opatch upgrade; it is the exact same procedure for a 11g opatch upgrade.



1/ Prerequisites

As prerequisites you need to have :
  • SSH passwordless connectivity set (as you want to patch an Exadata, we can assume that it is already done, if not, you can check in this post how to set SSH passwordless connectivity with dcli).
  • A text file containing the list of the nodes of the cluster, here it is /tmp/dbs_group
  • The opatch archive containing the latest version; I put it in /patches/opatch/p6880880_122010_Linux-x86-64.zip in my example

2/ Check the current opatch version

First, let's see how we can check the current opatch version :
myclusterdb01:oracle:\) dcli -g /tmp/dbs_group -l oracle /u01/app/oracle/product/12.1.0.2/dbhome_1/OPatch/opatch version
  myclusterdb01: OPatch Version: 12.1.0.1.8
  myclusterdb01:
  myclusterdb01: OPatch succeeded.
  myclusterdb02: OPatch Version: 12.1.0.1.8
  myclusterdb02:
  myclusterdb02: OPatch succeeded.
  myclusterdb03: OPatch Version: 12.1.0.1.8
  myclusterdb03:
  myclusterdb03: OPatch succeeded.
  myclusterdb04: OPatch Version: 12.1.0.1.8
  myclusterdb04:
  myclusterdb04: OPatch succeeded.
  myclusterdb05: OPatch Version: 12.1.0.1.8
  myclusterdb05:
  myclusterdb05: OPatch succeeded.
  myclusterdb06: OPatch Version: 12.1.0.1.8
  myclusterdb06:
  myclusterdb06: OPatch succeeded.
  myclusterdb07: OPatch Version: 12.1.0.1.8
  myclusterdb07:
  myclusterdb07: OPatch succeeded.
  myclusterdb08: OPatch Version: 12.1.0.1.8
  myclusterdb08:
  myclusterdb08: OPatch succeeded.
myclusterdb01:oracle:\)
This is not bad but let's add a "| grep Version" at the end of this command line to only have the opatch version as we are not interested in the other information returned :
myclusterdb01:oracle:\) dcli -g /tmp/dbs_group -l oracle /u01/app/oracle/product/12.1.0.2/dbhome_1/OPatch/opatch version | grep Version
myclusterdb01: OPatch Version: 12.1.0.1.8
myclusterdb02: OPatch Version: 12.1.0.1.8
myclusterdb03: OPatch Version: 12.1.0.1.8
myclusterdb04: OPatch Version: 12.1.0.1.8
myclusterdb05: OPatch Version: 12.1.0.1.8
myclusterdb06: OPatch Version: 12.1.0.1.8
myclusterdb07: OPatch Version: 12.1.0.1.8
myclusterdb08: OPatch Version: 12.1.0.1.8
myclusterdb01:oracle:\)
Better, isn't it ?

3/ Copy the opatch archive

To be able to unzip opatch on every node, we need to copy the archive on each node before. Let's copy it in /tmp
myclusterdb01:oracle:\) dcli -g /tmp/dbs_group -l oracle -f /patches/opatch/p6880880_122010_Linux-x86-64.zip -d /tmp
myclusterdb01:oracle:\)

4/ Upgrade opatch

Everything is now ready to upgrade opatch on each node (and yes, it is possible to do that in one command) :
myclusterdb01:oracle:\) dcli -g /tmp/dbs_group -l oracle "unzip -o /tmp/p6880880_122010_Linux-x86-64.zip -d /u01/app/oracle/product/12.1.0.2/dbhome_1; /u01/app/oracle/product/12.1.0.2/dbhome_1/OPatch/opatch version; rm /tmp/p6880880_122010_Linux-x86-64.zip" | grep Version
myclusterdb01: OPatch Version: 12.2.0.1.7
myclusterdb02: OPatch Version: 12.2.0.1.7
myclusterdb03: OPatch Version: 12.2.0.1.7
myclusterdb04: OPatch Version: 12.2.0.1.7
myclusterdb05: OPatch Version: 12.2.0.1.7
myclusterdb06: OPatch Version: 12.2.0.1.7
myclusterdb07: OPatch Version: 12.2.0.1.7
myclusterdb08: OPatch Version: 12.2.0.1.7
myclusterdb01:oracle:\)
Awesome, isn't it ? thanks dcli !


Deprecation of OPatch Command Option "-all_nodes"

A very important change will be happening soon (actually it has already happened) about opatch and then all the scripting you may have developed over the years. Indeed, the -all_nodes option will be deprecated and replaced as announced in Customer Recommended GI/RAC/Single Instance Announcing Deprecation of OPatch Command Option "-all_nodes" (Doc ID 2331762.1).

Details :

 This is applicable to all releases of OPatch.

 The 12.2.0.1.13 release (and later) of OPatch, which is used for all releases 12.1.0.x and later

 The 11.2.0.3.18 release (and later) of OPatch, which is used for all releases 11.2.0.1 - 11.2.0.4

 Beginning with these releases of OPatch,  OPatch will only support patching/listing inventory for local node of a RAC cluster.

 There will be no propagation to other nodes in cluster.

I first thought that this announcement was kind of awkward as we cannot imagine to have opatch to only support patching/listing inventory for local node of a RAC cluster. But it is not and after few tests, the -all_nodes option indeed does not provide any remote patch information any more in 12.2.0.1.13 which is not really nice.

Future :


Hopefully is also announced a new -remote option to replace -all_nodes but in the 12.2.0.1.14 version only :

1. In Opatch 12.2.0.1.13 and Opatch 11.2.0.3.18, OPatch command option “-all_nodes” will be no-op and existed in -help.

     If opatch command is being called with option “-all_nodes”, Opatch will print out the warning on console msg as:

     "OPatch was called with -all_nodes option. The -all_nodes option is being deprecated. Please remove it while calling OPatch."

 2.  In future release Opatch 12.2.0.1.14 (and later) and Opatch 11.2.0.3.20 (and later) , Option “-all_nodes” will be removed from -help, user will get syntax error if specify the option. 

Alternative Feature of -all_node is available  for Multi-Node GI/RAC :

$ORACLE_HOME/OPatch/opatchauto report -format xml -type patches -remote

(The remote command will get a list of patches from all nodes)


Indeed, 12.2.0.1.13 opatch now raises a warning when using the -all_nodes option :

oracle@exadatadb01> $ORACLE_HOME/OPatch/opatch lsinventory -all_nodes
Oracle Interim Patch Installer version 12.2.0.1.13
Copyright (c) 2018, Oracle Corporation.  All rights reserved.


Oracle Home       : /u01/app/12.2.0.1/grid
Central Inventory : /u01/app/oraInventory
   from           : /u01/app/12.2.0.1/grid/oraInst.loc
OPatch version    : 12.2.0.1.13
OUI version       : 12.2.0.1.4
Log file location : /u01/app/12.2.0.1/grid/cfgtoollogs/opatch/opatch2018-06-21_21-12-23PM_1.log

Warning: OPatch was called with -all_nodes option. The -all_nodes option is being deprecated.
         Please remove it while calling OPatch.

But do NOT provide any remote patch information any more.

How to use OCI Gen AI from the Linux command line

OCI Generative AI offers an on-demand service which you can access from your tenancy and pay only for what you use. This is very handy and...