Thursday, December 8, 2022

Prune GI/DB oui-patch.xml inventory files of old patches to speed up patching.

take these actions to subvert unpublished oracle bug 

Bug 33425636 – OPATCHAUTO VER 27 BINARIES APPLY TAKES LONG TIME

PROBLEM STATEMENT: 

  • The more patches you have historically applied, the longer the binary patching takes
  • The more cluster nodes you have, the longer it takes
  • The more databases you run on each cluster node, the longer it takes
  • The more PDBs you have, the longer it takes

readOuiPatch.py and pruneOuiPatch.py both written in python 2.7.5

- read inventory file

#!/bin/python

#
# readOuiPatch.py
#
import xml.etree.ElementTree as ET
import sys
import logging
import socket
import os
import os.path
if os.getenv('ORACLE_HOME'):
    l_orasid = os.getenv('ORACLE_SID')
    l_orahome = os.getenv('ORACLE_HOME')
else:
    print("environment not set.")
    sys.exit(1)
l_orasid = os.getenv('ORACLE_SID')
l_orahome = os.getenv('ORACLE_HOME')
l_fname="oui-patch.xml"
l_fname_path=l_orahome + "/inventory/ContentsXML/" + l_fname
if not os.path.exists(l_fname_path):
    print("")
    print("Inventory File:" + l_fname_path + ' does not exists or is not readable.')
    sys.exit(1)
else:
    print("")
    print("Inventory File:" + l_fname_path)
    print("")
tree = ET.parse(l_fname_path)
root = tree.getroot()
for oneoff in root.findall('ONEOFF'):
    desc = oneoff.find('DESC').text
    refid = oneoff.get('REF_ID')
    print(refid, desc)

-prune inventory file
# note: pass list of oneoff patch ids into this script.
#!/bin/python
#
# pruneOuiPatch.py
#
import xml.etree.ElementTree as ET
import sys
import logging
import socket
import os.path
import shutil
import datetime as dttm
def remove_patch(patch_id):
    l_out=''
    try:
        xmltree = ET.parse(l_fname_path)
        root = xmltree.getroot()
        for idx, oneoff in enumerate(root.findall('ONEOFF')):
            refid = oneoff.get('REF_ID')
            if refid==patch_id:
                root.remove(root[idx])
                xmltree.write(l_fname_path, encoding='UTF-8', xml_declaration=True)
                l_out=str(patch_id) + ':Removed'
                break
            else:
                l_out=str(patch_id) +':NotFound'
    except:
        l_out=str(patch_id) +':SomethingElse'
    return l_out
l_example= "    Example:"
l_example_msg = "    oracle> " + sys.argv[0] + " 1234,5678"
l_patch_list = []
l_fname = "oui-patch.xml"
# read patch list into py list.
if(len(sys.argv) == 2):
    l_patch_list=sys.argv[1].split(',')
elif(len(sys.argv) >= 3):
    print("")
    logging.critical("Too many variables provided.")
    print("")
    print(l_example)
    print(l_example_msg)
    sys.exit(1)
else:
    print("")
    logging.critical("No patchlist provided.")
    print("")
    print(l_example)
    print(l_example_msg)
    sys.exit(1)
if os.getenv('ORACLE_HOME'):
    l_orasid = os.getenv('ORACLE_SID')
    l_orahome = os.getenv('ORACLE_HOME')
else:
    print("")
    logging.critical("environment not set.")
    print("")
    sys.exit(1)
l_basedir = l_orahome + "/inventory/ContentsXML"
l_dttm = '.' + dttm.datetime.now().strftime('%Y%m%d_%H%M%S')
l_fname_path = l_basedir + "/" + l_fname
l_backup_fname_path = l_fname_path + l_dttm
if not os.path.exists(l_fname_path):
    print(l_fname_full + ' does not exists or is not readable.')
    sys.exit(1)
# backup existing oui-patch.xml file
shutil.copy(l_fname_path,l_backup_fname_path)
for patch in l_patch_list:
    print(remove_patch(str(patch)))
print("")
print("Inventory Base: " + l_basedir)
print("Inventory File: " + l_fname)
print("Backup: " + l_fname + l_dttm)



######
# sample execution

#######
oracle> echo $ORACLE_SID
CSBD818


(/opt/lbin)
oracle> echo $ORACLE_HOME
/opt/dev/oracle/product/db/19


(/opt/lbin)
oracle> ./readOuiPatch.py
Inventory File:/opt/dev/oracle/product/db/19/inventory/ContentsXML/oui-patch.xml
('29517242', 'Database Release Update : 19.3.0.0.190416 (29517242)')
('29585399', 'OCW RELEASE UPDATE 19.3.0.0.0 (29585399)')
('30894985', 'OCW RELEASE UPDATE 19.7.0.0.0 (30894985)')
('30869156', 'Database Release Update : 19.7.0.0.200414 (30869156)')
('32218454', 'Database Release Update : 19.10.0.0.210119 (32218454)')
('32222571', 'OCW Interim patch for 32222571')
('32545013', 'Database Release Update : 19.11.0.0.210420 (32545013)')
('33806152', 'Database Release Update : 19.15.0.0.220419 (33806152)')


oracle> ./pruneOuiPatch.py 29517242,29585399
29517242:Removed
29585399:Removed
Inventory Base: /opt/dev/oracle/product/db/19/inventory/ContentsXML
Inventory File: oui-patch.xml
Backup: oui-patch.xml.20221208_080047


oracle> ./readOuiPatch.py
Inventory File:/opt/dev/oracle/product/db/19/inventory/ContentsXML/oui-patch.xml
('30894985', 'OCW RELEASE UPDATE 19.7.0.0.0 (30894985)')
('30869156', 'Database Release Update : 19.7.0.0.200414 (30869156)')
('32218454', 'Database Release Update : 19.10.0.0.210119 (32218454)')
('32222571', 'OCW Interim patch for 32222571')
('32545013', 'Database Release Update : 19.11.0.0.210420 (32545013)')
('33806152', 'Database Release Update : 19.15.0.0.220419 (33806152)')
# patches removed from oui-patch.xml inventory. 
('29517242', 'Database Release Update : 19.3.0.0.190416 (29517242)')
('29585399', 'OCW RELEASE UPDATE 19.3.0.0.0 (29585399)')

credit and much thanks to Mike Dietrich for adding context and clarity on this bug. 
https://mikedietrichde.com/2022/05/10/binary-patching-is-slow-because-of-the-inventory/

good luck and happy patching. 

-huck