#!/bin/ksh
# DO NOT EDIT THIS FILE
#pragma ident   "@(#)hastat_common	1.1 98/06/17  SMI"

MEMBERSHIP="HASTAT_CURRENT_MEMBERSHIP"
CONFIG_STATE="HASTAT_CONFIG_STATE:"
UPTIME_STATE="HASTAT_UPTIME_STATE:"
LOGHOST_MASTERED="HASTAT_LOGICAL_HOSTS_MASTERED"
LOGHOST_BACKUP="HASTAT_LOGICAL_HOSTS_BACKUP:"
LOGHOST_MAINT="HASTAT_LOGICAL_HOSTS_MAINTENANCE" 
PRIVNET_STATUS="HASTAT_PRIV_NET_STATUS" 
PUBNET_STATUS="HASTAT_PUBLIC_NET_STATUS"
SERVICE_STATUS="HASTAT_SERVICE_STATUS"
RECENT_ERROR_MESG="HASTAT_RECENT_ERR_MSGS"

MEMBERSHIP_DESC="CURRENT MEMBERS OF THE CLUSTER"
CONFIG_STATE_DESC="CONFIGURATION STATE OF THE CLUSTER"
UPTIME_STATE_DESC="UPTIME OF NODES IN THE CLUSTER"
LOGHOST_MASTERED_DESC="LOGICAL HOSTS MASTERED BY THE CLUSTER MEMBERS"
LOGHOST_BACKUP_DESC="LOGICAL HOSTS WHICH HAVE BACKUP-NODES IN THE CLUSTER"
LOGHOST_MAINT_DESC="LOGICAL HOSTS IN MAINTENANCE STATE" 
PRIVNET_STATUS_DESC="STATUS OF PRIVATE NETS IN THE CLUSTER" 
PUBNET_STATUS_DESC="STATUS OF PUBLIC NETS IN THE CLUSTER"
SERVICE_STATUS_DESC="STATUS OF SERVICES RUNNING ON LOGICAL HOSTS IN THE CLUSTER"
RECENT_ERROR_MESG_DESC="RECENT  ERROR MESSAGES FROM THE CLUSTER"


set -A List "${MEMBERSHIP}"  "${CONFIG_STATE}"  "${UPTIME_STATE}"  "${LOGHOST_MASTERED}"  "${LOGHOST_MAINT}"  "${PRIVNET_STATUS}"  "${PUBNET_STATUS}"  "${SERVICE_STATUS}"  "${RECENT_ERROR_MESG}" 

set -A DescList "${MEMBERSHIP_DESC}"  "${CONFIG_STATE_DESC}"  "${UPTIME_STATE_DESC}"  "${LOGHOST_MASTERED_DESC}"  "${LOGHOST_MAINT_DESC}"  "${PRIVNET_STATUS_DESC}"  "${PUBNET_STATUS_DESC}"  "${SERVICE_STATUS_DESC}"  "${RECENT_ERROR_MESG_DESC}" 

#
# Copyright 21 Apr 1997 Sun Microsystems, Inc.  All Rights Reserved.
#
# pragma ident   "@(#)get_ha_status.sh	1.9 98/06/17  SMI"

# This File displays the Status of High Availablity Configuration 
# In Energizer Cluster Configuration.
#
# hastat_common file, which has all display formats, is prefixed to 
# this file by the Makefile


init()
{
        set -a
	integer i numnodes

        LD_LIBRARY_PATH=/opt/SUNWcluster/lib
        CLUSTERBIN=/opt/SUNWcluster/bin
        CLUSTERETC=/etc/opt/SUNWcluster
        CLUSTERVAR=/var/opt/SUNWcluster
        SSACLI=${CLUSTERBIN}/pdbssa
        PATH=$PATH:/usr/sbin:/usr/bin/:${CLUSTERBIN}:
	clustname=$(/bin/cat ${CLUSTERETC}/conf/default_clustername)
        # export CDB and LOGfile path.
        cdbfile=${CLUSTERETC}/conf/${clustname}.cdb
        cdbfilter=${CLUSTERETC}/conf/cdb.filter
        tmpdir=`enmatch env.tmpdir`
        admindir=${CLUSTERVAR}/admindir
	TMPDIR=${tmpdir}
	TMPSTATE=$TMPDIR/hastat_tmpstate.$$
	TMPERR=$TMPDIR/hastat_tmperr.$$
	TMPDB=$TMPDIR/hastat_tmpdb.$$
	TMPRDB=$TMPDIR/hastat_tmprdb.$$
	localhost=`uname -n`

	numnodes=`enmatch cluster.number.nodes`
	i=0
	allnodes=""
	while [ $i -lt $numnodes ]
	do
		allnodes="${allnodes} $i"
		i=i+1
	done

	set +a

}


function validate_env_vars
{
        set -a   

        currnodes=`${CLUSTERBIN}/clustm getcurrmembers $clustname`
        localnodeid=`${CLUSTERBIN}/clustm getlocalnodeid $clustname`
        allnodes=`${CLUSTERBIN}/clustm getallnodes ${clustname}`

	# convert currnodes to currmembers.
        currnodenames=""
        for i in ${currnodes}
        do
                name=`enmatch cluster.node.${i}.hostname`
                currnodenames="${currnodenames} ${name}"
        done

	# convert allnodes to currmembers.
        allnodenames=""
        for i in ${allnodes}
        do
                name=`enmatch cluster.node.${i}.hostname`
                allnodenames="${allnodenames} ${name}"
        done

	CCDFILE=$(${CLUSTERBIN}/ccdadm ${clustname} -w)
	ccdfile=$(${CLUSTERBIN}/ccdadm ${clustname} -w)

        set +a
}        

# lookup a value in the pdb configuration file
enmatch() {
        ${CLUSTERBIN}/cdbmatch $* ${cdbfile}
}

count_items()
{
        echo $#
}
 
get_first_item()
{
        echo $1
}

############################################################
# is_node_in_membership                                    #
#                                                          #
# Checks if the node is a cluster member                   #
# returns                                                  #
#       0 - If node is a cluster member.                   #
#       1 - If node is not a cluster member.               #
############################################################
function is_node_in_membership
{
        typeset checknode nodes
        typeset -i j

        checknode=$1

        # convert the current_nodes to current-names
        set -A nodes ${currnodenames}
        j=0
        while [ ! -z ${nodes[j]} ]
        do
                if [ ${nodes[j]} = ${checknode} ]; then
                        return 0;
                fi
                j=j+1;
        done
        return 1;

}


########################################################################
# get_the_monitor_host  <logical-host>  <backup_node>                  # 
# This function                                                        #
#       evaluates ${backup_node} to the backupnode.                    # 
########################################################################
function get_the_monitor_host
{
        typeset host loghostccd current_master nodeids default_master

        integer j
        integer anchor
        integer i

        host=$1

        # Get the CCD entry for LOGHOST.
        # XXX: should get -f <ccdfile>
        loghostccd=`${CLUSTERBIN}/scccd -f ${ccdfile} ${clustname} \
                        LOGHOST query lname ${host}`
        if [ -z ${loghostccd} ]; then
                return
        fi

        # get the current master from CCD.
        current_master=`${CLUSTERBIN}/scccd -f ${ccdfile} ${clustname} \
                        LOGHOST_CM query lname ${host} | \
                                /usr/bin/awk -F: '{ print $3}'`

        if [ -z ${current_master} ]; then
                #log_info "$pre.4601" "Could Not get LOGHOST_CM for ${host}"
                return
        fi
        # Get nnodelist
        nodeids=`echo ${loghostccd} | /usr/bin/awk -F: '{ print $3}' | \
                         /usr/bin/sed 's/,/ /'`

        # get default master
        default_master=$(get_first_item ${nodeids})

        # defensive check
        if [ ${current_master} = ${localhost} ]; then
                # error Should not happen
                echo "Error Framework Error for loghost_sync"
                return
        fi

        # 
        # check if default_master is not the current master
        # and if default master is up , then it is the backup host.
        #
        if [ ${default_master} != ${current_master} ]; then
                is_node_in_membership ${default_master}
                rval=$?
                if [ ${rval} = 0 ]; then
                        eval $2=${default_master}
                        return
                fi
        fi
        # now that we have to get the node which is best suited
        # for backup, get the anchor for the nodeid next to the
        # current master.
        set -A ccdnodes  ${nodeids}
        totalnodes=$(count_items ${nodeids})
        i=0
        while [ ! -z ${ccdnodes[i]} ]
        do
                if [ ${ccdnodes[i]} = ${current_master} ]; then
                        anchor=$i
                        break;
                fi
                i=i+1
        done

        i=`expr ${anchor} + 1`
        while [ ${i} != ${anchor} ]
        do
                if [ ${i} -eq ${totalnodes} ]; then
                        i=0
                fi
                is_node_in_membership ${ccdnodes[i]}
                rval=$?
                if [ ${rval} = 0 ]; then
                        eval $2=${ccdnodes[i]}
                        return
                fi
		if [ ${i} = ${anchor} ]; then
			break;
		fi
		i=i+1
        done

        eval $2=""
        return
}

########################################################################
# get_my_backup_logical_list                                           #
#                                                                      #
# This function gets the list of logical host names that this physical #
# host needs to monitor (NFS) from the <List of Logical Host Names Not #
# Mastered On this Node>                                               #
# Environment Variable: BACKUP_LOGICAL_HOSTS                           # 
########################################################################
function get_my_backup_list
{
        typeset logical_list i backup_node
        set -a
        logical_list=$1
        set +a

        for i in ${logical_list}
        do
                backup_node=""
                get_the_monitor_host ${i} backup_node
                if [ -z ${backup_node} ]; then
                # we do not have the backupnode for this.
                        continue;
                fi
                if [ ${backup_node} = ${localhost} ]; then
                        BACKUP_LOGICAL_HOSTS="${BACKUP_LOGICAL_HOSTS} ${i}"
                fi
        done
}

send_message()
{
	typeset message

	message=$*
	echo "${message}"
}


exit_from_hastat()
{
	echo "hastat:over"
	exit 0
}

config_state()
{
	#
	# First Determine if this is node is running as part of
	# the cluster.
	#
	send_message ${CONFIG_STATE}

	${CLUSTERBIN}/timed_run -q 3 ${CLUSTERBIN}/clustm getstate \
                        ${clustname} >/dev/null 2>&1 

	if [ $? -ne 0 ]; then
		# Node is not running as a part of the Cluster.
		send_message "     Configuration State on ${localhost} : Down"
		send_message ${CONFIG_STATE}
		send_message "${MEMBERSHIP}"
		send_message "     ${localhost} not a cluster member"
		send_message "${MEMBERSHIP}"
		return
	fi

	# Since it a part of the Cluster Validate ENV vars.

	validate_env_vars
	res=`${CLUSTERBIN}/clustm getstate ${clustname} 2>/dev/null`
	set -a
	if [ ${res} != "end" ]; then
		state="Reconfiguring"
	else
		state="Stable"
	fi

	set +a

	send_message "     Configuration State on ${localhost}: ${state}"
	send_message "${CONFIG_STATE}"
	send_message "${MEMBERSHIP}"
	send_message "     ${localhost} is a cluster member"
	send_message "${MEMBERSHIP}"

}


machine()
{
   typeset machine_result

   machine_result=`/usr/bin/uptime`
   send_message "${UPTIME_STATE}"
   send_message "     uptime of ${localhost}: "
   send_message "       ${machine_result}"
   send_message "${UPTIME_STATE}"

}


logical_hosts()
{
	#
	# Print Results Only if state=Stable
	#
	send_message "${LOGHOST_MASTERED}"
	if [ "$state" != "Stable" ]; then
		send_message "     ${localhost} is not a cluster member"
		send_message "${LOGHOST_MASTERED}"
                return
        fi

	mastered_list=`${CLUSTERBIN}/haget -f mastered`
	not_mastered_list=`${CLUSTERBIN}/haget -f not_mastered`

	send_message "Logical Hosts Mastered on ${localhost}:"
	if [ "${mastered_list}" = "" ]; then
		send_message "        None"
	else
		send_message "        ${mastered_list}"
	fi

	#
	# Get the List of Logical Hosts for which this node is
	# the Backup
	# XXX: Finally should have a call "haget -f me_backup"
	# XXX: Also need to add logical host in maintenance state.
	#
	get_my_backup_list "${not_mastered_list}"
	send_message "Loghost Hosts for which ${localhost} is Backup Node:"
	if [ "${BACKUP_LOGICAL_HOSTS}" = "" ]; then
		send_message "        None"
	else
		send_message "        ${BACKUP_LOGICAL_HOSTS}"
	fi
	send_message "${LOGHOST_MASTERED}"

	allinfo=$(${CLUSTERBIN}/scccd -f ${CCDFILE} ${clustname} \
		LOGHOST_MSTATE query mmode 0)
	if [ "${allinfo}" !=  "" ]; then
		send_message "${LOGHOST_MAINT}"
		echo         "        \c"
		for i in ${allinfo}
		do
			lname=`echo ${i} | awk -F: ' {print $2} '`
			echo "${lname} \c"
		done
		echo ""
		send_message "${LOGHOST_MAINT}"
	fi
	
}

interconnect_status() {

	typeset i active_file select_file select net0 net1

        net0=unknown
        net1=unknown

        if [  -r ${cdbfile} ] ; then
                active_file=`${CLUSTERBIN}/cdbmatch ccm.script.topnet.file ${cdbfile}`
                select_file=`${CLUSTERBIN}/cdbmatch ccm.script.net.file ${cdbfile}`

                if [ -f ${active_file} -a -f ${select_file} ] ; then
                        #  find which nets are up by looking at active file contents
                        #  active file contents can be:
                        #               0 1
                        #               0
                        #               1
                        for i in `/bin/cat ${active_file}`
                        do
                                case "${i}" in
                                        '0') net0=up
                                                ;;
                                        '1') net1=up
                                                ;;
                                        *)
                                                ;;
                                esac
                        done

                        #  set the nets that aren't up to be down
                        #  active file only contains up nets
                        if [ "$net0" = "unknown" ] ; then
                                net0=down
                        fi
                        if [ "$net1" = "unknown" ] ; then
                                net1=down
                        fi

                        #  find selected net from select file
                        #  only nets that are up can be selected
                        #  select file contain one char (0 or 1) to
                        #  designate selected net
                        select=`/bin/cat ${select_file}`
                        if [ "X${select}" = "X0" ] ; then
                                if [ "${net0}" = "up" ] ; then
                                        net0=selected
                                fi
                        elif [ "X${select}" = "X1" ] ; then
                                if [ "${net1}" = "up" ] ; then
                                        net1=selected
                                fi
                        fi

                fi
        fi
        echo "        interconnect0: ${net0}"
        echo "        interconnect1: ${net1}"
}

priv_nets()
{
	typeset name i
	typeset privateIP

	send_message "${PRIVNET_STATUS}" 
	send_message "     Status of Interconnects on ${localhost}:"
	interconnect_status

	send_message "     Status of private nets on ${localhost}:"
	#
	# From allnode in the cluster, get the hahost for that
	# node. It gives up the IP address.
	# Then Ping it , if it succeeds then Private Nets Are UP.
	# (XXXX: In future if we have failure fencing if ports then
	# i would suggest that we display this information only 
	# when required.
	#
	for i in ${allnodes}
	do
		name=`enmatch cluster.node.${i}.hostname`
		privateIP=`enmatch cluster.node.${i}.hahost`

		/usr/sbin/ping -n ${privateIP} 2 >/dev/null 2>&1

		RC=$?
	
		if [ ${RC} -ne 0 ]; then
			/usr/sbin/ping -n ${name} 2 >/dev/null 2>&1
			if [ $? -eq 0 ]; then
				send_message "        To ${name} - Down" 
			else
				send_message "        To ${name} - Unknown" 
			fi
		else
				send_message "        To ${name} - UP" 
		fi
	done
	send_message "${PRIVNET_STATUS}" 

}


pub_nets()
{
	#
	# Will PNMSTAT to the status of all adapters..
	# Sundeep Has told me that he will provide it.
	#
	send_message "${PUBNET_STATUS}"
	if [ "$state" != "Stable" ]; then
		send_message "Status of Public Network On ${localhost}:\n"
		send_message "     Public Net Monitoring Not running on ${localhost}"
		send_message "${PUBNET_STATUS}"
		return
	fi
	send_message "Status of Public Network On ${localhost}:\n"
	/usr/bin/pkginfo SUNWpnm >/dev/null 2>&1
	RC=$?

	if [ ${RC} -eq 0 ]; then
		# PNM packages are present, so use pnmstat -a
		# should display  it.
		# /opt/SUNWpnm/bin/pnmstat -a
		/opt/SUNWpnm/bin/pnmstat -l 2>/dev/null
	else
		#
		# PNM package is not present , so cannot do much
		#
		send_message "     No Public Network status support as of Now"
	fi
	send_message "${PUBNET_STATUS}"
}


data_services()
{
	typeset newlist
	typeset row


        #
        # Only print results if state=Stable.
        #
	send_message "${SERVICE_STATUS}"
        if [ "$state" != "Stable" ]; then
		send_message "     No Data Service Running on ${localhost}"
		send_message "${SERVICE_STATUS}"
                return
        fi


	#
	# For each service that is ON in the Cluster.
	# Get the List of logical hosts Mastered.
	# And Also for which this node is the Backup which are
	# offering the services.
	# Call the Status routines. for the same
	# (now only for NFS etc..)
	#
	allinfo=$(${CLUSTERBIN}/scccd -f ${CCDFILE} ${clustname} DS_INFO \
			query ds_name "")

	allsvcon=""
	for i in ${allinfo}
	do
		svc=`echo ${i} | /bin/awk -F: ' {print $2} '`
		TEST=`/opt/SUNWcluster/bin/haget -f service_is_on \
					-s ${svc} 2>/dev/null`
		if [ ${TEST} -ne 1 ]; then
			continue;
		fi
		allsvcon="${allsvcon} ${svc}"
	done

	if [ "${allsvcon}" = "" ]; then
		send_message "     No Data Services are Running/Configured on ${localhost}"
		send_message "${SERVICE_STATUS}"
		return
	fi

	send_message "Status Of Data Services Running On ${localhost}"

	for i in ${allsvcon}
	do
		svc=${i}

		mastered_list=`/opt/SUNWcluster/bin/haget -f mastered`

		rows=$(${CLUSTERBIN}/scccd -f ${CCDFILE} ${clustname} \
			LOGHOST_DS query dsname ${svc})
		newlist=""
		for r in ${rows}; do
		    loghost_name=${r%:*}
		    loghost_name=${loghost_name#*:}
		    cm_row=$(${CLUSTERBIN}/scccd -f ${CCDFILE} ${clustname} \
				LOGHOST_CM query lname ${loghost_name})
		    cm=${cm_row#*:*:}
		    if [ "${cm}" = "${localhost}" ]; then
			newlist="${newlist} ${loghost_name}"
		    fi
		done
		if [ "${newlist}" = "" ]; then
			send_message "     Status of ${svc}:"
			send_message "     No Logical host is configured for this data service"
			continue;
		fi

		case ${svc} in
		 nfs)
			echo "      Data Service HA-NFS: "
			
			/opt/SUNWcluster/ha/nfs/nfs_stat "${newlist}"
			;;
		
                oracle|sybase|informix)
                        iupper=`echo $i|/bin/tr [a-z] [A-Z]`
                        echo "      Data Service HA-${iupper}:"
                        DBMS_SIDS=`${i}_status_svcs`
                        if [ "$DBMS_SIDS" != "" ]; then
                                echo "    DataBase Status on ${localhost} :"
                                for j in $DBMS_SIDS; do
                                        echo "        $j - \c"
                                        res=`${i}_status $j`
                                        echo "${res}; "
                                done
                                echo ""
                        fi
			;;
		*)
			echo "      No Status Method for Data Service ${svc}\n"
			;;

		esac
	done
	send_message "${SERVICE_STATUS}"

}


recent_err_msgs()
{
	send_message	"${RECENT_ERROR_MESG}"
	send_message	"Recent Error Messages on ${localhost}\n"
	/bin/egrep -i 'SUNWcluster:.*notice:|warning|error|fatal|4???|[^a-zA-Z] (soc|pln|ssd|sd)[^a-zA-Z]|[^a-zA-Z](be|le|qe|hme|nf)[0-9]+:|ID[.*SUNWcluster.*\]:'  /var/adm/messages | /bin/tail -${recent_err_lines}
	send_message    "${RECENT_ERROR_MESG}"
}

get_hostnames()
{
	typeset i filelist list commalist list1
	
	# Following sentence is indicates the start of of net info
	# haopen() depends on this string for processing. So do not
	# change the sentence. 
	echo "LIST OF NAMES ON NETWORK"

        list=""
        filelist=$(/usr/bin/ls /etc/hostname.*[0-9])
        for i in ${filelist}
        do
                if [ -z ${list} ]; then
                        list=$(/usr/bin/cat ${i})
                else
                        list="${list} $(/usr/bin/cat ${i})"
                fi
        done

	#
	# ATM lan emulation do not put the entries in
	# /etc/hostname.* ; They remove these entries in
	# S00sunatm in /etc/rc2.d
	# Format of /etc/atmconfig (see man page of atmconfig)
	#
	# Physical-Interface Uni-Ver C-IPHost LaneInstance LaneHost
	#
	# See more information in man page of "atmconfig(4)" in 
	# /opt/SUNWatm/man/man4.

	# This will gather all the Lan Emulation Host.
	if [ -f /etc/atmconfig ]; then
	  list1=`grep -v \^# /etc/atmconfig | grep "ba[0-9]" | \
        	awk ' $5 != "-" { print $5 } '`
	  list="${list} ${list1}"
	fi

	# This code below will gather all the Classical Ip Host
	if [ -f /etc/atmconfig ]; then
	  list1=`grep -v \^# /etc/atmconfig | grep "ba[0-9]" | \
        	awk ' $3 != "-" { print $3 } '`
	  list="${list} ${list1}"
	fi

        # Remove all unnecessary blanks
        # The requester expects a comma seperated list
        commalist=""
        for i in ${list}
        do
                if [ -z ${commalist} ]; then
                        commalist=${i}
                else
                        commalist="${commalist},${i}"
                fi
        done
        echo ${commalist}
}

#
# First set the PATH so that we can execute all our functions.
# Get the BASEDIR and PRODUCTDIR settings from the installed pkgs

_basedir_etc=`/bin/pkgparam SUNWecscf BASEDIR 2>/dev/null`

# for oracle
_basedir=`/bin/pkgparam SUNWecor BASEDIR 2>/dev/null`
_productdir=`/bin/pkgparam SUNWecor PRODUCTDIR 2>/dev/null`
_basedir_etc=${_basedir_etc:=""}
_basedir=${_basedir:=""}
_productdir=${_productdir:="SUNWcluster"}
_oraclepath=${_basedir}/${_productdir}/ha/oracle
# for normal path and bin
PATH=/usr/sbin/:/usr/bin/:/sbin/:/bin/:${_oraclepath}:/opt/SUNWcluster/bin:/opt/SUNWcluster/ha/nfs/:

argv0=$(/bin/basename $0)
res=$(/bin/id)
if [ `expr "$res" : "uid=\([0-9]*\)("` != 0 ] ; then
        echo "$argv0 must be executed as super-user." >&2
        exit 1
fi

trap "/bin/rm -f $TMPSTATE $TMPERR $TMPDB $TMPRDB; exit_from_hastat; exit" 1 2 13 15

arg1=$1

# If this is only to find hostnames
if [ "${arg1}" == "-hostname" ]; then
	get_hostnames
	exit_from_hastat
fi

if [ "${arg1}" = "" ]; then
	recent_err_lines=10
else
	recent_err_lines=${arg1}
fi

init
echo ""

config_state

machine
priv_nets

logical_hosts
pub_nets
data_services
recent_err_msgs
exit_from_hastat
