#!/bin/bash
# Fred Denis -- Nov 2017 -- fred.denis3@gmail.com -- http://unknowndba.blogspot.com
# exa-versions.sh - show a nice summary of the versions of each component of an Exadata stack (DB servers, Cells and Switches) (https://bit.ly/38XfPAx)
# Copyright (C) 2021 Fred Denis
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see .
#
#
# More info and git repo: https://bit.ly/38XfPAx -- https://github.com/freddenis/oracle-scripts
#
# The current script version is 20211111
#
# History :
#
# 20211111 - Fred Denis - GPLv3 licence, ib/roce have no status so cannot be shown in red
# 20211018 - Fred Denis - oraenv not needed here so I removed it; cosmetic
# 20200715 - Fred Denis - Manage the ROCE switches which come with X8M+
# Keep in mind that you can deploy the SSH keys to the ROCE switches using /opt/oracle.SupportTools/RoCE/setup_switch_ssh_equiv.sh
# 20190528 - Fred Denis - Fixed a bug on the headers
# 20190524 - Fred Denis - Better management of the naming of the hosts, cells and IB
# 20180913 - Fred Denis - Add the status = failure information for the Cells and DB Servers
#
#
# Variables
#
DBMACHINE=/opt/oracle.SupportTools/onecommand/databasemachine.xml # File where we should find the Exadata model
SHOW_ALL="Yes"
SHOW_DBS="No"
SHOW_CELLS="No"
SHOW_IBS="No"
NB_PER_LINE=$(bc <<< "`tput cols`/22") # Number of element to print per line
# -- default adapts to the size of the screen (thanks to tput)
# -- can be changed at script execution with the -n option
# From X8M, we have no way of dynamycally know the nodes so we have to rely on hardcoded lists
X8M_DBS_GROUP="${HOME}/dbs_group"
X8M_CELL_GROUP="${HOME}/cell_group"
X8M_ROCE_GROUP="${HOME}/roce_group"
ROCE_USER="ciscoexa"
#
# Check if ibhosts works (if not, we are on X8M+)
#
ibhosts > /dev/null 2>&1
if [ $? -ne 0 ]; then
X8M="True"
else
X8M="False"
fi
#
# usage function
#
usage() {
printf "\n\033[1;37m%-8s\033[m\n" "NAME" ;
cat << END
exa-versions.sh - show a nice summary of the versions of each component of an Exadata stack (DB servers, Cells and Switches) (https://bit.ly/38XfPAx)
END
printf "\n\033[1;37m%-8s\033[m\n" "SYNOPSIS" ;
cat << END
$0 [-d] [-c] [-i] [-n] [-C] [-D] [-R] [-I] [-h]
END
printf "\n\033[1;37m%-8s\033[m\n" "DESCRIPTION" ;
cat << END
$0 needs to be executed as root and the ssh keys to each Exadata component have to be deployed
With no option $0 will show the versions of all the Exadata components (DB servers, Cells and IB)
If a DB servers or cell has a status = failure returned by the imageinfo command, the host will appear
in red and a note about this will be shown at the end of the report
END
printf "\n\033[1;37m%-8s\033[m\n" "OPTIONS" ;
cat << END
-d Show the Database servers versions
-c Show the Cells (storage servers) versions
-i Show the Switches versions (IB if < X8M, ROCE if X8M+)
-r Show the Switches versions (IB if < X8M, ROCE if X8M+)
-C A specific cell_group file
-D A specific dbs_group file
-R A specific roce_group file
-I A specific ib_group file
-n Number of nodes to show per line (default adapts the output to the current screen size)
-h Shows this help
END
exit 123
}
#
# Options management
#
while getopts "dcirn:D:C:I:R:h" OPT; do
case ${OPT} in
d) SHOW_ALL="No"; SHOW_DBS="Yes"; ;;
D) SHOW_ALL="No"; SHOW_DBS="Yes"; P_DBS_GROUP="${OPTARG}" ;;
c) SHOW_ALL="No"; SHOW_CELLS="Yes" ;;
C) SHOW_ALL="No"; SHOW_CELLS="Yes"; P_CELL_GROUP="${OPTARG}" ;;
i) SHOW_ALL="No"; SHOW_IBS="Yes" ;;
I) SHOW_ALL="No"; SHOW_IBS="Yes"; P_IB_GROUP="${OPTARG}" ;;
r) SHOW_ALL="No"; SHOW_IBS="Yes" ;;
R) SHOW_ALL="No"; SHOW_IBS="Yes"; P_IB_GROUP="${OPTARG}" ;;
n) NB_PER_LINE=${OPTARG} ;;
h) usage ;;
\?) echo "Invalid option: -$OPTARG" >&2; usage ;;
esac
done
#
# Show the Exadata model if possible
#
if [ -f "${DBMACHINE}" ] && [ -r "${DBMACHINE}" ]; then
cat << !
Cluster is a `grep -i MACHINETYPES ${DBMACHINE} | sed s'/\t*//' | sed -e s':*MACHINETYPES>::g' -e s'/^ *//' -e s'/ *$//'`
!
else
printf "\n"
fi
#
# Fill the tempfiles
#
if [[ "${X8M}" = "False" ]] ; then
if [[ -n "${P_DBS_GROUP}" ]]; then
DBS_GROUP="${P_DBS_GROUP}"
else
DBS_GROUP=$(mktemp -u)
ibhosts | grep db | grep -v cel | sed s'/"//g' | awk '{print $6}' > ${DBS_GROUP}
TO_DELETE1="${DBS_GROUP}"
fi
if [[ -n "${P_CELL_GROUP}" ]]; then
CELL_GROUP="${P_CELL_GROUP}"
else
CELL_GROUP=$(mktemp -u)
ibhosts | grep cel | sed s'/"//g' | awk '{print $6}' > ${CELL_GROUP}
TO_DELETE2="${CELL_GROUP}"
fi
if [[ -n "${P_IB_GROUP}" ]]; then
IB_GROUP="${P_IB_GROUP}"
else
IB_GROUP=$(mktemp -u)
ibswitches | awk '{print $10}' > ${IB_GROUP}
TO_DELETE3="${IB_GROUP}"
fi
else
if [[ -n "${P_DBS_GROUP}" ]]; then
DBS_GROUP="${P_DBS_GROUP}"
else
DBS_GROUP="${X8M_DBS_GROUP}"
fi
if [[ -n "${P_CELL_GROUP}" ]]; then
CELL_GROUP="${P_CELL_GROUP}"
else
CELL_GROUP="${X8M_CELL_GROUP}"
fi
if [[ -n "${P_IB_GROUP}" ]]; then
IB_GROUP="${P_IB_GROUP}"
else
IB_GROUP="${X8M_ROCE_GROUP}"
fi
fi
( if [[ "$SHOW_DBS" = "Yes" ]] || [[ "$SHOW_ALL" = "Yes" ]] && [[ -f "${DBS_GROUP}" ]]
then
dcli -g ${DBS_GROUP} -l root "imageinfo -ver -status" | sort | awk -F ": " '{if(node==""){node=$1}; if($2 != "") {status=$3; getline; printf ("%s:%s:%s:%s\n","db", node, $3, status); node="" ;}}'
echo ""
fi
if [[ "$SHOW_CELLS" = "Yes" ]] || [[ "$SHOW_ALL" = "Yes" ]] && [[ -f "${CELL_GROUP}" ]]
then
dcli -g ${CELL_GROUP} -l root "imageinfo -ver -status" | grep "Active" | sort | awk -F ": " '{if(node==""){node=$1}; if($2 != "") {status=$3; getline; printf ("%s:%s:%s:%s\n","cel", node, $3, status); node="" ;}}'
echo ""
fi
if [[ "$SHOW_IBS" = "Yes" ]] || [[ "$SHOW_ALL" = "Yes" ]]
then
if [[ -f "${IB_GROUP}" ]] ; then
if [[ "${X8M}" = "False" ]]; then
dcli -g ${IB_GROUP} -l root version | grep -v BIOS | grep "version:" | awk '{print "ib:", $1, $NF}' | sort
else
# dcli does not seem to work with the roce switches
for S in $(cat ${IB_GROUP} | sort); do
ssh -q ${ROCE_USER}@${S} show version | grep "NXOS: version" | awk -v SWITCH="${S}" '{print "ib:", SWITCH":", $NF}'
done
fi
fi
echo ""
fi
)\
| awk -v NB_PER_LINE="$NB_PER_LINE" -v X8M="${X8M}" ' BEGIN \
{ FS = ":" ;
# some color
COLOR_BEGIN = "\033[1;" ;
COLOR_END = "\033[m" ;
RED = "31m" ;
GREEN = "32m" ;
YELLOW = "33m" ;
BLUE = "34m" ;
TEAL = "36m" ;
WHITE = "37m" ;
# Columns size
COL_SIZE = 20 ;
# Some variables
nb_node = 0 ;
FAILURES = 0 ;
}
function print_a_line(size) {
printf("%s", COLOR_BEGIN WHITE) ;
for (k=1; k<=size;k++) {printf("%s", "-");} ;
printf("%s", COLOR_END"\n") ;
}
#
# A function to center the outputs with colors
#
function center(str, n, color) {
right = int((n - length(str)) / 2) ;
left = n - length(str) - right ;
return sprintf(COLOR_BEGIN color "%" left "s%s%" right "s" COLOR_END, "", str, "" ) ;
}
{ if ($0 !~ /^$/) {
nb_node++ ;
type = $1 ;
db_node[nb_node] = $2 ;
db_version[nb_node] = $3 ;
db_status[nb_node] = $4 ;
while (getline) {
if ($0 ~ /^$/) {
# A Header
if (type == "db") {printf("%s\n", center("-- Database Servers", 40,RED))};
if (type == "cel") {printf("%s\n", center("-- Cells", 30,RED))};
if (type == "ib") {
if (X8M == "False") {
printf("%s\n", center("-- Infiniband Switches", 40,RED)) ;
} else {
printf("%s\n", center("-- ROCE Switches", 40,RED)) ;
}
}
printf("\n") ;
version_ref = db_version[1] ;
for (a=0; a 0) {
printf("%s", center(db_node[i],COL_SIZE,COLOR)) ;
nb_printed++ ;
}
}
printf("\n") ;
print_a_line(COL_SIZE*nb_printed+NB_TO_SHOW) ;
# Print the nodes versions
for (i=a+1; i<=a+NB_PER_LINE; i++) {
if (length(db_version[i]) > 0) {
if (db_version[i] == version_ref) {
A_COLOR=BLUE ;
} else {
A_COLOR=TEAL ;
}
printf("%s", center(db_version[i],COL_SIZE,A_COLOR));
}
}
printf("\n") ;
print_a_line(COL_SIZE*nb_printed+NB_TO_SHOW) ;
printf("\n\n") ;
} # END for (a=0; a