#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG                                                    
#  This is an automatically generated prolog.                                  
#                                                                              
#  Copyright (C) Altran ACT S.A.S. 2017,2021.  All rights reserved.  
#                                                                              
#  ALTRAN_PROLOG_END_TAG                                                      
#                                                                              
# @(#)  7d4c34b 43haes/usr/sbin/cluster/cspoc/utilities/cl_pviddisklist.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
###############################################################################
#   COMPONENT_NAME: CSPOC
#
# Name:
#   cl_pviddisklist
#
# Description
#   This script is passed, via stdin, a series of lines of the form
#	node: hdisk_name:pvid:<ignored>
#   It is also given as formal parameter a comma separated list of node names.
#   This should be all possible node names that can occur in the list.
#
#   It will collect common references to the same PVID and hdisk
#
#   Output written to stdout in the following format:
#
#   pvid    (hdisk_name on node node_name [at site site_name])
#
#   Or, if the same hdisk name is used on multiple nodes:
#
#   pvid    (hdisk_name on nodes node_name,node_name[,node_name...] [at site site_name])
#
#   Or, if the hdisk name is the same across the given list of nodes
#
#   pvid    (hdisk_name on all cluster nodes)
#
#
#   Usage: ... | cl_pviddisklist [-c | -P] [-u] NodeList
#
#   -c	    colon delimited output
#   -P	    formatted for pick list
#   -u      input contains UUIDs as one of the last field,
#           and they are significant for disambiguating disks
#
# Return Values:
#       0       success
#       1       failure
#
###############################################################################

PROGNAME=${0##*/}
[[ -n $_DEBUG ]] &&
    print "DEBUG $PROGNAME version 1.10"

WORK_FILE=/tmp/clpviddisklist.$$
rm -f $WORK_FILE		    # work file
_MSET=43			    # message file
export ODMDIR=/etc/objrepos
short_pvids=""
pvid_nodelist=""
colon_output=""
picklist_output=""
integer hdisk_max=0
integer hdisk_size=0
typeset -A sitenodes
uuid_check=""

while getopts 'Pcu' option
do
    case $option in
	c ) :	Colon delimited output requested
	    colon_output=true
	    ;;

	P ) :	Pick list format output requested
	    picklist_output=true
	    ;;

	u ) :   UUID check for identical disk test, too
	    uuid_check=true
	    ;; 
    esac
done
shift $((OPTIND - 1))

#
:   Sorted version of given node list, for reliable comparison
#
s_target_nodes=$(print $1 | tr ',' '\n' | sort | paste -s -d, -)
s_all_cluster_nodes=$(IFS=, set -- $(/usr/es/sbin/cluster/utilities/clnodename | sort) ; print "$*")
site_list=$(/usr/es/sbin/cluster/utilities/clodmget -f name -n HACMPsite)
for site in $site_list
do
    sitenodes[$site]=$(IFS=, set -- $(/usr/es/sbin/cluster/utilities/clodmget -q "name = $site" -f nodelist -n HACMPsite) ; print "$*" )
done


#
:   Compress the list of disks so that disks of the same name on
:   different nodes are collected into a comma separated node list
#
    node_list=""
    #
    :	Sort the list of available disks by PVID, disk name, and node so that
    :	we can collect the list of nodes that know the disk by the same name
    #
    sort -u -t':' -k3,3 -k2,2 -k1,1 |
	( while IFS=: read node hdiskname pvid rest ; do

	    if [[ -z $node_list ]]
	    then
		#
		:   First pass through loop
		#
		node_list=$node
		oldpvid=$pvid
		oldhdiskname=$hdiskname
		oldrest=$rest 

	    elif [[ $pvid != $oldpvid  || $hdiskname != $oldhdiskname ]] || \
	         [[ -n $uuid_check && $oldrest != $rest ]] 
	    then
		#
		:   The line that was just read is not the same disk and name
		:   as the previous ones.  So, print out what has been collected up
		:   till now
		#
		if [[ -n ${node_list}${oldhdiskname}${oldpvid} ]]
		then
		    print ${node_list}: ${oldhdiskname}:$oldpvid:$oldrest
		fi

		#
		:   And reset the node list for the disk we just read
		#
		node_list=$node
		oldpvid=$pvid
		oldhdiskname=$hdiskname
		oldrest=$rest
	    else
		#
		:   Collect the names of the nodes that know this disk by the same name
		#
		node_list=${node_list},$node
	    fi
	done
    #
    :   Print any last line
    #
    if [[ -n ${node_list}${oldhdiskname}${oldpvid} ]]
    then
	print ${node_list}: ${oldhdiskname}:$oldpvid:$oldrest
    fi) > $WORK_FILE

    #
    :	Check to make sure we have some output
    #
    if [[ ! -s $WORK_FILE ]]
    then
        msg_line=$(dspmsg -s 43 cspoc.cat 6 "No free disks found.");
        printf '# %s\n' "${msg_line}"
        msg_line=$(dspmsg -s 43 cspoc.cat 42 "Check each node to see if any disks need to have PVIDs allocated.");
        printf '# %s\n' "${msg_line}"
        if [[ -e $WORK_FILE ]]
        then
            rm -f $WORK_FILE                #   Clean up empty work file
        fi
        return 1
    fi

    #
    :   At this point, the file /tmp/clpviddisklist.$$ contains lines of the form
    :	node[,node,..]: hdisk_name:pvid
    :   However, there is no guarantee that a given disk is actually known
    :   on all nodes in the given node list.  So, another pass through the 
    :	file is necessary to collect the node lists from successive lines that 
    :	refer to the same  PVID, and check them against the given node list.
    #
    cat $WORK_FILE |  while IFS=: read node_list hdiskname pvid rest
    do
	if [[ -z $pvid_nodelist ]]
	then
	    #
	    :   First pass through loop
	    #
	    pvid_nodelist=$node_list
	    oldpvid=$pvid
            oldrest=$rest  

	elif [[ $pvid != $oldpvid ]] ||\
             [[ -n $uuid_check && $oldrest != $rest ]]
	then
	    #
	    :   The PVID that was just read, $pvid, is not the same as the
	    :   previous one, $oldpvid.  So, check the node list so far
	    #
	    s_pvid_nodelist=$(print $pvid_nodelist | tr ',' '\n' | sort -u | paste -s -d, -)
            if [[ -n $s_target_nodes && $s_pvid_nodelist != $s_target_nodes ]] ||
               [[ -z $s_target_nodes && $s_pvid_nodelist != @(*,*) ]]
            then
		#
		:   The sorted list of nodes on which $oldpvid is known,
		:   $s_pvid_nodelist, is not the same as the list of nodes in
		:   the resource group, $s_target_nodes.  Or, \"\$s_target+nodes
		:   was not given, but $oldpvid is known on only a single node.
		:   So, add $oldpvid to the list of those that have to be 
		:   excluded from the final display.  Note the use of "|" as a 
		:   delimiter, to serve as an "or" function with egrep below.
		#
		short_pvids=${short_pvids:+$short_pvids"|"}${oldpvid}
	    fi
	    oldpvid=$pvid
	    oldrest=$rest  
	    pvid_nodelist=$node_list

	else
	    #
	    :   Collect the names of nodes that know this disk, though
	    :   under different hdisk names
	    #
	    pvid_nodelist=${pvid_nodelist},$node_list
	fi
    done
    #
    :   Process the last line
    #
    s_pvid_nodelist=$(print $pvid_nodelist | tr ',' '\n' | sort -u | paste -s -d, -)
    if [[ -n $s_target_nodes && $s_pvid_nodelist != $s_target_nodes ]] ||
       [[ -z $s_target_nodes && $s_pvid_nodelist != @(*,*) ]]
    then
        #
        :   The sorted list of nodes on which $oldpvid is known,
        :   $s_pvid_nodelist, is not the same as the list of nodes in
        :   the resource group, $s_target_nodes.  Or, \"\$s_target+nodes
        :   was not given, but $oldpvid is known on only a single node.
        :   So, add $oldpvid to the list of those that have to be 
	:   excluded from the final display.  Note the use of "|" as a 
	:   delimiter, to serve as an "or" function with egrep below.
        #
	short_pvids=${short_pvids:+$short_pvids"|"}${oldpvid}
    fi

    #
    :   Remove those disks which do not appear on all the nodes in the
    :   given node list, and print out the rest.  The sorting is first by
    :   PVID, and then by hdisk name for that PVID.
    #
    (   if [[ -n $short_pvids ]]
	then
	    egrep -v -w $short_pvids $WORK_FILE
	else
	    cat $WORK_FILE
	fi ) | 
    sort -t: -k3,3 -k2.7,2n |
    while IFS=: read node_list hdiskname pvid rest
    do
	hdiskname=$(print $hdiskname)       #   trim leading blanks
        hdisk_size=${#hdiskname}
        hdisk_max=$(( hdisk_size > hdisk_max ? hdisk_size : hdisk_max ))

	if [[ $colon_output == "true" ]]
	then
	    print "${node_list}:${hdiskname}:${pvid}"

	elif [[ $picklist_output == "true" ]]
	then
	    #
	    :   Here turn the line into a user friendly form
	    #
	    pvid='('${pvid}')'
	    fmt_node_list=""
	    if [[ $s_all_cluster_nodes == $node_list ]]
	    then
		#
		:   On all cluster nodes
		#
		fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 43 "%s on all cluster nodes" $pvid)
	    
	    else
		#
		:   Check to see if this disk is known on all nodes at a specific site
		#
		for site in $site_list
		do
		    site_nodes=${sitenodes[$site]}
		    if [[ $site_nodes == $node_list ]]
		    then
			fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 52 "%s on all nodes at site %s" $pvid $site)
			break
		    fi
		done
	    fi

	    if [[ -z $fmt_node_list ]]
	    then
		if [[ $s_target_nodes == $node_list ]]
		then
		    #
		    :   On all selected nodes
		    #
		    fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 21 "%s on all selected nodes" $pvid)

		else
		    #
		    :   Check to see if this disk is site specific
		    #
		    for site in $site_list 
		    do
			#
			:	Get the list of nodes at each site, and see if the node list is
			:	entirely contained at that site
			#
			site_nodes=${sitenodes[$site]}
			pvid_site=$site
			for node in $(IFS=, set -- $node_list ; print $*)
			do
			    if ! print $site_nodes | grep -qw $node
			    then
				#
				:   $node from $node_list is not in $site_nodes
				#
				pvid_site=""
				break
			    fi
			done
			if [[ -n $pvid_site ]]
			then
			    #
			    :   All nodes in $node_list are in $site_nodes
			    #
			    break
			fi
		    done

		    if [[ $node_list == @(*,*) ]]
		    then
			#
			:   Construct output line for hdisk name at multiple nodes
			#
			if [[ -n $pvid_site ]]
			then
			    fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 22 "%s on nodes %s at site %s" $pvid $node_list $pvid_site)
			else
			    fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 23 "%s on nodes %s" $pvid $node_list)
			fi
		    else
			#
			:   Construct output line for hdisk name at single node
			#
			if [[ -n $pvid_site ]]
			then
			    fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 24 "%s on node %s at site %s" $pvid $node_list $pvid_site)
			else
			    fmt_node_list=$(dspmsg -s ${_MSET} cspoc.cat 25 "%s on node %s" $pvid $node_list)
			fi
		    fi
		fi
	    fi
	    #
	    :   Put out the line for this PVID
	    #
	    typeset -L${hdisk_max} hdisk_name="$hdiskname"
	    print "$hdisk_name" $fmt_node_list

	else
	    #
	    :   Here turn the line into a user friendly form
	    #
	    if [[ $s_all_cluster_nodes == $node_list ]]
	    then
		#
		:   On all cluster nodes
		#
		node_list=$(dspmsg -s ${_MSET} cspoc.cat 43 "%s on all cluster nodes" $hdiskname)

	    elif [[ $s_target_nodes == $node_list ]]
	    then
		#
		:   On all selected nodes
		#
		node_list=$(dspmsg -s ${_MSET} cspoc.cat 21 "%s on all selected nodes" $hdiskname)

	    else
		#
		:   Check to see if this disk is site specific
		#
		pvid_site=$(clodmget -q "name=PVID and value = $pvid" -f site -n HACMPsiteinfo)

		if [[ $node_list == @(*,*) ]]
		then
		    #
		    :   Construct output line for hdisk name at multiple nodes
		    #
		    if [[ -n $pvid_site ]]
		    then
			node_list=$(dspmsg -s ${_MSET} cspoc.cat 22 "%s on nodes %s at site %s" $hdiskname $node_list $pvid_site)
		    else
			node_list=$(dspmsg -s ${_MSET} cspoc.cat 23 "%s on nodes %s" $hdiskname $node_list)
		    fi
		else
		    #
		    :   Construct output line for hdisk name at single node
		    #
		    if [[ -n $pvid_site ]]
		    then
			node_list=$(dspmsg -s ${_MSET} cspoc.cat 24 "%s on node %s at site %s" $hdiskname $node_list $pvid_site)
		    else
			node_list=$(dspmsg -s ${_MSET} cspoc.cat 25 "%s on node %s" $hdiskname $node_list)
		    fi
		fi
	    fi
	    #
	    :   Put out the line for this PVID
	    #
	    print $pvid "(" $node_list ")"
	fi
    done

[[ -z $_DEBUG ]] &&
    rm $WORK_FILE

return 0;
