@@ -171,6 +171,10 @@ def setup(self):
171171 self .updateasmdevices ()
172172 else :
173173 pass
174+ if self .ocommon .check_key ("RUN_DATAPATCH" ,self .ora_env_dict ):
175+ self .run_datapatch ()
176+ else :
177+ pass
174178
175179
176180 ct = datetime .datetime .now ()
@@ -786,3 +790,84 @@ def listasminstname(self):
786790 print (sid )
787791 else :
788792 print ("NOT READY" )
793+
794+ def run_datapatch (self ):
795+ """
796+ Function to check and apply Oracle database patches using OPatch and Datapatch.
797+ """
798+ self .ocommon .log_info_message ("Starting run_datapatch()" , self .file_name )
799+ rundatapatch = self .ora_env_dict .get ("RUN_DATAPATCH" , "" ).strip ().lower () in ["true" , "1" , "yes" ]
800+
801+ self .ocommon .log_info_message (f"Running datapatch with passed argument: { rundatapatch } " , self .file_name )
802+
803+ if not rundatapatch :
804+ self .ocommon .log_info_message ("RUN_DATAPATCH is not set to true. Skipping datapatch execution." , self .file_name )
805+ return
806+ dbuser , dbhome , dbbase , oinv = self .ocommon .get_db_params ()
807+ self .ocommon .log_info_message ("ORACLE_HOME set to " + dbhome , self .file_name )
808+ self .ocommon .log_info_message ("ORACLE_USER set to " + dbuser , self .file_name )
809+ self .ocommon .log_info_message ("ORACLE_BASE set to " + dbbase , self .file_name )
810+
811+ dbname , osid , dbuname = self .ocommon .getdbnameinfo ()
812+ hostname = self .ocommon .get_public_hostname ()
813+ inst_sid = self .ocommon .get_inst_sid (dbuser , dbhome , osid , hostname )
814+ self .ocommon .log_info_message ("ORACLE_SID set to " + inst_sid , self .file_name )
815+
816+ if not all ([inst_sid , dbbase , dbhome , dbuser ]):
817+ self .ocommon .log_info_message ("Missing required Oracle environment variables." , self .file_name )
818+ return
819+
820+ # Export required environment variables
821+ env_setup_cmd = "export ORACLE_SID={0}; export ORACLE_HOME={1}; export ORACLE_BASE={2}; " .format (inst_sid , dbhome , dbbase )
822+
823+ # Fetch patches from OPatch
824+ cmd_lspatches = '''su - {0} -c "{1} {2}/OPatch/opatch lspatches"''' .format (dbuser , env_setup_cmd , dbhome )
825+ output , error , retcode = self .ocommon .execute_cmd (cmd_lspatches , None , None )
826+ self .ocommon .check_os_err (output , error , retcode , None )
827+
828+ if retcode != 0 :
829+ self .ocommon .log_info_message ("Failed to fetch OPatch patches." , self .file_name )
830+ return
831+
832+ opatch_patches = {line .split (";" )[0 ].strip () for line in output .splitlines () if ";" in line }
833+ self .ocommon .log_info_message ("OPatch Patches: " + str (opatch_patches ), self .file_name )
834+
835+ # Fetch patches from DBA_REGISTRY_SQLPATCH with proper ORACLE_SID export
836+ sql_query = "SELECT PATCH_ID FROM DBA_REGISTRY_SQLPATCH;"
837+ cmd_sqlpatch = '''su - {0} -c "{1} echo \\ "{2}\\ " | sqlplus -S / as sysdba"''' .format (dbuser , env_setup_cmd , sql_query )
838+ output , error , retcode = self .ocommon .execute_cmd (cmd_sqlpatch , None , None )
839+ self .ocommon .check_os_err (output , error , retcode , None )
840+
841+ if retcode != 0 :
842+ self .ocommon .log_info_message ("Failed to fetch DBA_REGISTRY_SQLPATCH patches." , self .file_name )
843+ return
844+
845+ sqlpatch_patches = {line .strip () for line in output .splitlines () if line .strip ().isdigit ()}
846+
847+ # Compare patch lists
848+ missing_patches = opatch_patches - sqlpatch_patches
849+ extra_patches = sqlpatch_patches - opatch_patches
850+
851+ self .ocommon .log_info_message ("OPatch Patches: " + str (opatch_patches ), self .file_name )
852+ self .ocommon .log_info_message ("SQL Patch Patches: " + str (sqlpatch_patches ), self .file_name )
853+
854+ if not missing_patches and not extra_patches :
855+ self .ocommon .log_info_message ("All patches are correctly applied." , self .file_name )
856+ else :
857+ if missing_patches :
858+ self .ocommon .log_info_message ("These patches are missing in DBA_REGISTRY_SQLPATCH: " + str (missing_patches ), self .file_name )
859+ self .ocommon .log_info_message ("Running datapatch..." , self .file_name )
860+
861+ cmd_datapatch = '''su - {0} -c "{1} {2}/OPatch/datapatch -skip_upgrade_check"''' .format (dbuser , env_setup_cmd , dbhome )
862+ output , error , retcode = self .ocommon .execute_cmd (cmd_datapatch , None , None )
863+ self .ocommon .check_os_err (output , error , retcode , None )
864+
865+ if retcode == 0 :
866+ self .ocommon .log_info_message ("Datapatch execution completed successfully." , self .file_name )
867+ else :
868+ self .ocommon .log_info_message ("Datapatch execution failed." , self .file_name )
869+
870+ if extra_patches :
871+ self .ocommon .log_info_message ("These patches appear in DBA_REGISTRY_SQLPATCH but not in OPatch: " + str (extra_patches ), self .file_name )
872+
873+ self .ocommon .log_info_message ("End run_datapatch()" , self .file_name )
0 commit comments