0% found this document useful (0 votes)
19 views22 pages

Lspatches

The version of the script is 20190906 20190906 - Fred Denis - A new -V option to show the version of the script 20191401 - Fred Denis - opatchauto report: show Homes with -s option properly, fixed GREP/UNGREP - Fixed issue with GI HOMe with no olsnodes (non-RAC) 20190401 - Fred Denis - Implement opatchauto report instead of lsinventory -all_nodes for versions > 1220112 or for 11g 20180809 - Fred Denis - Add the desription of a patch if available 20180704 - Fred Denis - GRE

Uploaded by

ingjguedez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
19 views22 pages

Lspatches

The version of the script is 20190906 20190906 - Fred Denis - A new -V option to show the version of the script 20191401 - Fred Denis - opatchauto report: show Homes with -s option properly, fixed GREP/UNGREP - Fixed issue with GI HOMe with no olsnodes (non-RAC) 20190401 - Fred Denis - Implement opatchauto report instead of lsinventory -all_nodes for versions > 1220112 or for 11g 20180809 - Fred Denis - Add the desription of a patch if available 20180704 - Fred Denis - GRE

Uploaded by

ingjguedez
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 22

#!

/bin/bash

# Fred Denis -- [email protected] -- June 22nd 2018

# Please have a look at https://unknowndba.blogspot.com/2018/07/lspatchessh-oracle-patch-


reporting-tool.html for detailed explanations

# Provide information on the installed and missing patches on ORACLE_HOMEs

# $0 -h for more information

# The version of the script is 20190906

# 20190906 - Fred Denis - A new -V option to show the version of the script

# 20191401 - Fred Denis - opatchauto report: show Homes with -s option properly, fixed
GREP/UNGREP

# - Fixed issue with GI HOMe with no olsnodes (non-RAC)

# 20190401 - Fred Denis - Implement opatchauto report instead of lsinventory -all_nodes for
versions > 1220112 or for 11g

# 20180809 - Fred Denis - Add the desription of a patch if available

# 20180704 - Fred Denis - GREP and UNGREP now works when a file is specified

# A new -o option to only get the opatch output on a file

# The -s option is now compatible with the -f one

# 20180626 - Fred Denis - Started the opatch version management by showing a warning when the
special 12.2.0.1.13 and 11.2.0.3.18 versions are used

# see https://unknowndba.blogspot.com/2018/06/deprecation-of-opatch-
command-option.html for more information

# Shows an error when opatch raises an error (when another user owns the
ORACLE_HOME for example)

# 20180625 - Fred Denis - Different OS support : (the script is developed under Linux)

# --- Solaris :

# - grep "^[Aa-Zz|+]" does not work on Solaris so I moved to grep -v "^#" | grep -v
"^$" when reading oratab

# - default Solaris awk is the original awk and nawk lacks features from gawk (the
script definitely does not work with nawk due to array management features)
# gawk is installed by default with Solaris 11 and is available for Solaris < 11, the
script then expects gawk to be here for Solaris and if not it cannot continue

# --- HP-UX and AIX :

# - The "case" to support other OS is also HP-UX and AIX ready but I have not tested it
as I have no such OS handy

# 20180622 - Fred Denis - Initial release

# Default values

ALL_NODES="Yes" # RAC system

GREP="." # What we grep -- default is everything

UNGREP="nothing_to_ungrep_unless_v_option_is_used$$" # What we don't grep (grep -v) --


default is nothing

FILE="" # No input file

OUT="" # No output file

TMP=/tmp/fictemplspatches$$ # A tempfile

TMP2=/tmp/fictemplspatches2$$ # Another tempfile

SHOW_HOMES="NO" # YES or NO we want to show the Homes from


/etc/oratab or the input file $FILE ONLY

# Show the version of the script (-V)

show_version()

VERSION=`awk '{if ($0 ~ /^# 20[0-9][0-9][0-1][0-9]/) {print $2; exit}}' $0`

printf "\n\t\033[1;36m%s\033[m\n" "The current version of "`basename $0`" is "$VERSION"."


;
}

# An usage function

usage()

printf "\n\033[1;37m%-8s\033[m\n" "NAME" ;

cat << END

$0 -- Provide information on the installed and missing patches on ORACLE_HOMEs

END

printf "\n\033[1;37m%-8s\033[m\n" "SYNOPSIS" ;

cat << END

$0 [-f] [-o] [-g] [-l] [-v] [-s] [-h]

END

printf "\n\033[1;37m%-8s\033[m\n" "DESCRIPTION" ;

cat << END

$0 relies on the content of the /etc/oratab file to look at the installed patch on the
ORACLE_HOMEs

It uses the opatch installed on each Home to list the installed patches and find the missing
ones in case of RAC system

A file containing some opatch outputs can also be provided to $0; it will then not use opatch
but rely on the input file

oraenv has to work as it is used to check if it is a RAC installation with olsnodes

If olsnodes from the ASM Home returns no rows then we go with local opatch

END

printf "\n\033[1;37m%-8s\033[m\n" "OPTIONS" ;

cat << END


-f A file containing one or more opatch outputs (no opatch command is performed in this
mode)

- not compatible with the -o option

- compatible with the -g and -v options

-o An output file if you just want to generate the opatch output (no patch analysis shown)

- not compatible with the -f option

- compatible with the -g and -v options

-l Run opatch as Local only (default is opatch is run using the -all_nodes option)

-g Act as a grep command to grep the Homes you want to have the patches information

Examples :

$0 -g 12 # Will only consider the Homes that contain "12" in


their name

$0 -g /u01/app/oracle/product/12.1.0.2/dbhome_dr2 # Will only consider this home

$0 -g dbhome_1 # Will only consider the Homes containing


"dbhome_1"

$0 -g dbhome_1 -f /tmp/opatchoutput # Will only consider


the Homes containing "dbhome_1"in the /tmp/opatchoutput file

-v Act as a grep -v comnmand when selecting the Homes you want the patches information
from; it can be combined with the -g option

Examples :

$0 -v 12 # Will NOT consider the Homes which have"12" in their


name

$0 -g dbhome_1 -v 12 # Will consider the "dbhome_1" Homes BUT those


containing "12" in their name

$0 -v grid # All the Homes but the "grid" ones

-s Show the ORACLE_HOMEs that would be considered by the script, it can be used in
conjunction with the -g and -v options
You can then test your -g and -v combination here

Examples :

$0 -s # Show all Homes from /etc/oratab

$0 -g 12 -v oa -s # Show all "12" Homes BUT the "oa" ones

$0 -f /tmp/opatchoutput -g 12 -s # Show the Homes from an


opatch output file for the "12" Homes only

-V Shows the version of the script

-h Shows this help

END

exit 123

# Parameters management

while getopts "lg:v:f:o:hsV" OPT; do

case ${OPT} in

f) FILE=${OPTARG} ;;

o) OUT=${OPTARG} ;;

g) GREP=${OPTARG} ;;

l) ALL_NODES="" ;;

v) UNGREP=${OPTARG} ;;

s) SHOW_HOMES="YES" ;;

V) show_version; exit 567 ;;

h) usage ;;

\?) echo "Invalid option: -$OPTARG" >&2; usage ;;

esac

done
#

# Different OS support

OS=`uname`

case ${OS} in

SunOS)

ORATAB=/var/opt/oracle/oratab

AWK=/usr/bin/gawk ;;

Linux)

ORATAB=/etc/oratab

AWK=`which awk` ;;

HP-UX)

ORATAB=/etc/oratab

AWK=`which awk` ;;

AIX)

ORATAB=/etc/oratab

AWK=`which awk` ;;

*) echo "Unsupported OS, cannot continue."

exit 666 ;;

esac

if [ ! -f ${ORATAB} ]

then

cat << !

Unable to find oratab file in ${ORATAB}, cannot continue.

!
exit 667

fi

if [ ! -f ${AWK} ]

then

cat << !

Cannot find a modern version of awk in ${AWK}, cannot continue.

exit 668

fi

if [[ -n ${FILE} && -n ${OUT} ]]

then

cat << END

The -f and -o options cannot be used together; cannot continue.

$0 -h for help

END

exit 669

fi

# Show Homes only if -s option specified

if [ ${SHOW_HOMES} = "YES" ]

then

if [[ -f ${FILE} ]]

then

printf "\n\033[1;37m%-8s\033[m\n\n" "ORACLE_HOMEs that would be considered ($


{FILE}) :" ;

cat ${FILE} | grep "^Oracle Home" | awk 'BEGIN {FS=":"} { printf("\t%s\n", $NF)}' |
grep ${GREP} | grep -v ${UNGREP} | sort | uniq
cat ${FILE} | grep "homes path=" | uniq | sed s'/" .*$//' | sed s'/.*"//' | sort | grep $
{GREP} | grep -v ${UNGREP}

else

printf "\n\033[1;37m%-8s\033[m\n\n" "ORACLE_HOMEs that would be considered ($


{ORATAB}) :" ;

cat ${ORATAB} | grep -v "^#" | grep -v "^$" | grep -v agent | awk 'BEGIN {FS=":"}
{ printf("\t%s\n", $2)}' | grep ${GREP} | grep -v ${UNGREP} | sort | uniq

fi

printf "\n"

exit 0

fi

# Check that the file in parameter exists

if [ ! -f ${FILE} ]

then

cat << !

File ${FILE} does not exist, cannot proceed.

exit 123

fi

# Check if we could write in the out file

if [[ -n ${OUT} ]]

then

if [ -d ${OUT} ]; then echo "${OUT} is a directory, please specify a regular file; cannot
continue."; exit 670; fi
if [ ! -w `dirname ${OUT}` ] ; then echo "`dirname ${OUT}` is not writable; cannot continue.";
exit 671; fi

fi

# Set the ASM env to be able to use crsctl commands as well as olsnodes

ORACLE_SID=`ps -ef | grep pmon | grep asm | awk '{print $NF}' | sed s'/asm_pmon_//' | egrep
"^[+]"`

# No ASM then we go local (I would need a RAC config with FS to test)

if [ -z ${ORACLE_SID} ]

then

ALL_NODES=""

else

export ORAENV_ASK=NO

. oraenv > /dev/null 2>&1

# Check if it is a RAC installtion, if not we go Local with opatch

if [ ! -f ${ORACLE_HOME}/bin/olsnodes ]

then

ALL_NODES=""

else

if [[ $(olsnodes | wc -l) -eq "0" ]] # No RAC installed so we go local only

then

ALL_NODES=""
fi

fi

fi

if [ -z ${FILE} ] # If a file as parameter we do not do the opatch

then

cat /dev/null > ${TMP}

for OH in `cat ${ORATAB} | grep -v "^#" | grep -v "^$" | grep -v agent | awk 'BEGIN {FS=":"}
{ print $2}' | grep ${GREP} | grep -v ${UNGREP} | sort | uniq`

do

printf "%-80s" "Proceeding with ${OH} . . ."

if [ -f $OH/OPatch/opatch ] && [ -x $OH/OPatch/opatch ]

then

OPATCH_DOTTED_VERSION=`$OH/OPatch/opatch version | grep Version | awk '{print


$NF}'`

ERR=$?

if [ ${ERR} -eq 0 ]

then

OPATCH_VERSION=`echo ${OPATCH_DOTTED_VERSION} | sed s'/\.//g'`

if [[ "${OPATCH_VERSION:0:2}" -eq "12" && "${OPATCH_VERSION}" -gt


1220112 ]] ||

[[ "${OPATCH_VERSION:0:2}" -eq "11" && "${OPATCH_VERSION}" -gt


1120318 ]]

then # remote

if [ "${ALL_NODES}" = "Yes" ]

then

ALL_NODES_OPTION=" -remote "

else

ALL_NODES_OPTION=""
fi

echo "Oracle Interim Patch Installer version "$OPATCH_DOTTED_VERSION


>> ${TMP}

$OH/OPatch/opatchauto report -type patches -format xml $


{ALL_NODES_OPTION} >> ${TMP} 2>${TMP2}

ERR=$?

else # lsinventory

if [ "${ALL_NODES}" = "Yes" ]

then

ALL_NODES_OPTION=" -all_nodes "

else

ALL_NODES_OPTION=""

fi

$OH/OPatch/opatch lsinventory ${ALL_NODES_OPTION} -oh ${OH}


>> ${TMP} 2>${TMP2}

ERR=$?

fi

if [ ${ERR} -eq 0 ]

then

printf "\t\033[1;32m%-8s\033[m\n" "OK" ;

else

printf "\t\033[1;31m%-8s" "Error $ERR" ;

cat ${TMP2} ;

printf "\033[m\n" "" ;

fi

else

printf "\t\033[1;31m%-8s" "Error " ;

fi
#if (((substr(OPATCH_VERSION_NUMERIC,1,2) == 12) &&
(OPATCH_VERSION_NUMERIC > 1220112)) ||

# ((substr(OPATCH_VERSION_NUMERIC,1,2) == 11) &&


(OPATCH_VERSION_NUMERIC > 1120318)))

#$OH/OPatch/opatch lsinventory ${ALL_NODES} -oh ${OH} >> ${TMP} 2>${TMP2}

#ERR=$?

#if [ ${ERR} -eq 0 ]

#then

# printf "\t\033[1;32m%-8s\033[m\n" "OK" ;

#else

# printf "\t\033[1;31m%-8s" "Error " ;

# cat ${TMP2} ;

# printf "\033[m\n" "" ;

#fi

else #if [ -f $OH/OPatch/opatch ] && [ -x $OH/OPatch/opatch ]

printf "\t\033[1;31m%-8s" "Cannot find $OH/OPatch/opatch " ;

printf "\033[m\n" "" ;

fi

done

else

cp ${FILE} ${TMP}

fi

#echo $TMP

#exit

# An output file is specified, we just want the opatch output so we exit before analyzing the opatch
output
#

if [[ -n ${OUT} ]]

then

if [ -f ${TMP} ]

then

cp ${TMP} ${OUT}

if [ $? -ne 0 ]

then

cat << END

Could not copy the tempfile into ${OUT}; the opatch output should be in ${TMP};

END

fi

rm -f ${TMP}

exit $?

fi

fi

printf "\n" ;

${AWK} -v GREP="$GREP" -v UNGREP="$UNGREP" -v


OPATCH_DOTTED_VERSION="$OPATCH_DOTTED_VERSION"\

'BEGIN { FS = ":" ;

# some colors

COLOR_BEGIN = "\033[1;" ;

COLOR_END = "\033[m" ;

RED = "31m" ;

GREEN = "32m" ;

YELLOW = "33m" ;
BLUE = "34m" ;

TEAL = "36m" ;

WHITE = "37m" ;

UNKNOWN = "-" ; # Something to print when the status is unknown

# Default columns size

COL_NODE = 16 ;

COL_PATCH = 12 ;

COL_VER = 14 ;

# A function to center the outputs with colors

function center( str, n, color, sep)

{ right = int((n - length(str)) / 2) ;

left = n - length(str) - right ;

return sprintf(COLOR_BEGIN color "%" left "s%s%" right "s" COLOR_END sep, "", str, "" )
;

# A function that just print a "---" white line

function print_a_line()

printf("%s", COLOR_BEGIN WHITE) ;

for (k=1; k<=WIDTH; k++) {printf("%s", "-");} ; # n = number


of nodes
printf("%s", COLOR_END"\n") ;

# The function that prints the output in nice tables

function print_output()

WIDTH = COL_PATCH+COL_NODE*n+n+1 ;

printf(COLOR_BEGIN BLUE" %s"COLOR_END, OH) ; # OH as a title

if (OPATCH_VERSION == "")

{ OPATCH_VERSION="unknown; opatchauto report does not provide the opatch version";

printf(" %s\n", "(opatch version " OPATCH_VERSION")") ; # Opatch version

# A header

print_a_line() ;

printf("%s", center("Patch ID", COL_PATCH, WHITE, "|")) ;

for (i = 1; i <= n; i++)

printf("%s", center(nodes[i], COL_NODE, WHITE, "|")) ; # Hostname / nodes

printf("\n") ;

print_a_line() ;

some_patches=0 ;

p=asort(all_patches) ;

for (i = 1; i <= p; i++)

some_patches=1 ;

printf("%s", center(all_patches[i], COL_PATCH, WHITE, "|")) ;


for (j = 1; j <= n; j++) # for each node

if (patch_tab[nodes[j], all_patches[i]] == all_patches[i]) # Patch is here

{ printf("%s", center("-", COL_NODE, GREEN, "|")) ;

else # Patch is missing

printf("%s", center("Missing", COL_NODE, RED, "|")) ;

printf ("%s", descr[all_patches[i]]) ; # Patch description

printf "\n" ;

if (some_patches == 0)

{ printf("%s\n", center("No patch installed ", WIDTH-1, TEAL, "|")) ;

delete all_patches ;

delete patch_tab ;

delete nodes ;

delete descr ;

NB_PATCHES_INSTALLED=0 ;

print_a_line() ;

printf "\n" ;

# Main awk

#
{ if ($0 ~ /^Oracle Interim Patch Installer version/)

{ gsub(/([aA-zZ])| /, "", $0) ;

OPATCH_VERSION=$0 ;

gsub(/\./, "", $0) ;

OPATCH_VERSION_NUMERIC=$0 ;

if ($1 ~ /^Oracle Home/) # opatch lsinventory output

gsub(" ", "", $2) ;

OH=$2 ;

oh_tab[oh_nb++]=OH ;

if ((OH !~ GREP) || (OH ~ UNGREP))

next ;

while (getline)

if ($1 ~ /^Hostname/) # The hostname in


case it is a local opatch

gsub(" ", "", $2) ;

sub(/\..*$/, "", $2) ;

SERVER = $2 ;

nodes[1] = $2 ;

n=1 ;

if (($1 ~ /^Rac system comprising/) && (! NB_PATCHES_INSTALLED))


# RAC Home

{
cpt=1 ;

while(getline)

{ if ($0 ~ /^$/)

{ break ;

gsub(" ", "", $0) ;

gsub(/^.*=/, "", $0) ;

nodes[cpt] = $0 ;

cpt++ ;

n=asort(nodes) ; # sort array nodes

if (($1 ~ /^Patch level status of Cluster node/) && (! NB_PATCHES_INSTALLED))


# Grid Homes

{ getline; getline; getline;

nodes_list = "" ;

while(getline)

if ($0 ~ /^$/)

split(nodes_list, nodes, ",") ;

n=asort(nodes) ; # sort array nodes

break ;

if ($1 ~ /^ *[0-9]* /)

sub(/^ *[0-9]* /, "", $1);

gsub(" ", "", $1) ;


gsub("\t", "", $1) ;

if (nodes_list == "")

{ nodes_list = $1 ;

} else {

nodes_list=nodes_list","$1 ;

if ($1 ~ /^Node Name/)

gsub(" ", "", $2) ;

SERVER=$2 ;

if ($1 ~ /^Interim patches/)

gsub(/^.*\(/, "", $1) ;

gsub(/\).*$/, "", $1) ;

NB_PATCHES_INSTALLED = $1 ;

NB_PATCHES_FOUND = 0 ;

while(getline)

if (($1 ~ /^Patch/) && ($0 ~ /applied on/)) # Patch id

{ NB_PATCHES_FOUND++ ;

patch_id = $1 ;

sub("Patch", "", patch_id) ;

gsub(" ", "", patch_id) ;


patch_tab[SERVER, patch_id]=patch_id ; # Patches
per server

if (patch_id in all_patches)

{ cpt++; } else {

all_patches[patch_id] = patch_id ; # All patches


accross all nodes

getline; getline ;

if ($1 ~ /^Patch description/) # Get the patch


descr if available

sub("Patch description: ", "", $0) ;

gsub("\"", "", $0) ;

descr[patch_id] = $0 ;

if (NB_PATCHES_FOUND == NB_PATCHES_INSTALLED)

{ break ;

if (($1 ~ /^OPatch succeeded/) || ($1 ~ /^OPatch completed with warnings/))

print_output() ;

break ;

} # End if ($1 ~ /^Oracle Home/)

if ($0 ~ /OPatchAuto report result/) # opatchauto report output


{

n=0 ; # Number of nodes

while (getline)

{ if ($0 ~ /host name=/)

{ sub(/^.*name="/, "", $0) ;

sub(/".*$/, "", $0) ;

SERVER=$0 ;

n++ ;

nodes[n]=SERVER ;

if ($0 ~ /homes path/)

{ sub(/^.*path="/, "", $0) ;

sub(/".*$/, "", $0) ;

OH=$0 ;

if ((OH !~ GREP) || (OH ~ UNGREP))

next ;

if($0 ~ /patch id/)

patch_id = $0 ;

sub(/^ *<patch id="/, "", patch_id) ;

sub(/".*$/, "", patch_id) ;

patch_tab[SERVER, patch_id]=patch_id ; # Patches per server

if (patch_id in all_patches)

{ cpt++; } else {

all_patches[patch_id] = patch_id ; # All patches accross all nodes

}
}

if ($0 ~ /OPatchAuto report end of result/)

{ print_output() ;

break ;

} ' ${TMP}

for F in ${TMP} ${TMP2}

do

if [ -f ${F} ]

then

rm -f ${F}

fi

done

#************************************************************************#

#* END OF SOURCE *#

#************************************************************************#

You might also like