#!/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
#
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r721 src/43haes/usr/sbin/cluster/events/utils/cl_update_vg_odm_ts.sh 1.13 
#  
# Licensed Materials - Property of IBM 
#  
# Restricted Materials of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2013,2016 
# All Rights Reserved 
#  
# US Government Users Restricted Rights - Use, duplication or 
# disclosure restricted by GSA ADP Schedule Contract with IBM Corp. 
#  
# IBM_PROLOG_END_TAG 
# @(#)  7d4c34b 43haes/usr/sbin/cluster/events/utils/cl_update_vg_odm_ts.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
#  
#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================

################################################################################
#
#   Name:       update_vg_odm_ts
#
#   Function:   Given a volume group, check to see if any disk in the volume 
#               group has a time stamp different from the time stamp for the
#               volume group in ODM.  If so, update the ODM time stamp to match
#               that of the disk.
#
#               Then, update the time stamp in the ODMs of any other nodes in 
#               the resource group that owns this volume group.
#
#
#   Input:      Volume group name, optionally followed by node list
#
#               If only the volume group name is given, the time stamps are 
#               updated on the nodes in the resource group containing the volume
#               group.  
#               If a node list is given, the volume group time stamps are updated
#               on all nodes in the list.  The node list is a list of PowerHA 
#               node names, either space or comma separated.
#
#
#   Output:     return code = 0 - volume group time stamp successfully updated
#               return code = 1 - no volume group name provided
#               return code = 2 - cannot read volume group VGID from ODM
#               return code = 3 - cannot read current volume group time stamp
#                                 from ODM
#
#   Notes:      This routine only updates the volume group timestamps in ODM on
#               the various nodes.  It does not do a true synchronization of the
#               volume group metadata.  It is intended to deal with the fact
#               that, varying off a volume group updates the time stamps, and 
#               only recent versions of LVM automatically propagate that change
#               to other nodes.  Updating these time stamps across the cluster
#               avoids problem reports on the next verify and sync, and possibly
#               long recovery times.
#
#################################################################################
if [[ $VERBOSE_LOGGING == 'high' ]]
then
    PS4_TIMER=true
    set -x
    version='1.13'
fi

#################################################################################
#
#   Name:	lspv_in_vg
#
#   Function:	Given the name of a volume group, find the names of the hdisks in
#		that volume group by direct query of CuAt.
#
#		This direct query of CuAt avoids LVM locking and other overhead 
#		that is significant with very large numbers of disks and volume
#		groups.
#
#   Input:	Volume group name
#
#   Output:	hdisk names in the volume group written to stdout, one per line
#
#################################################################################
function lspv_in_vg {
    
    if [[ $VERBOSE_LOGGING == 'high' ]]
    then
	PS4_FUNC='lspv_in_vg'
	set -x
    fi

    typeset vg_name=$1

    clodmget -q "name = $vg_name and attribute = pv" -f value -n CuAt | 
    while read pvid ; 
    do
	#
	:   Find the name of the disk with PVID $pvid
	#
	clodmget -q "value = $pvid and attribute = pvid" -f name -n CuAt
    done
}

################################################################################
#
#   MAIN    Main    main
#
#
o_flag=""
f_flag=""
while getopts ':of' option
do
    case $option in
	o ) :	Local timestamps should be good, since volume group was 
	    :	just varyied on or off
	    o_flag=TRUE
	    ;;

	f ) :	Update timestamps clusterwide, even if LVM support is in
	    :	place
	    f_flag=TRUE
	    ;;

	* ) :
	    dspmsg -s 4 cspoc.cat 26 "$PROGNAME: Invalid option [$option].\n" $PROGNAME $option
	    return 1
	    ;;
    esac
done
shift $((OPTIND - 1))

vg_name=$1
if [[ -z $vg_name ]]
then
    print "cl_update_vg_odm_ts <volume group name> [<node list>]"
    return 1            #   Bad input - missing volume group name
fi

shift
node_list=$*
PATH=$(/usr/es/sbin/cluster/utilities/cl_get_path all)

if [[ -z $f_flag ]]
then
    ################################################################################
    :   Check to see if this update is necessary - some LVM levels automatically 
    :   update volume group timestamps clusterwide.
    #
    #   Complex check below needed to catch various versions of LVM efix
    #
    if instfix -iqk IV74100 > /dev/null 2>&1 ||
       instfix -iqk IV74883 > /dev/null 2>&1 ||
       instfix -iqk IV74698 > /dev/null 2>&1 ||
       instfix -iqk IV74246 > /dev/null 2>&1
    then	
        #
        :    LVM APAR installed which makes timestamp update unnecessary
        #
        return 0
    fi

    if ( $(emgr -l -L IV74883 2>/dev/null >&2) || $(emgr -l -L IV74698 2>/dev/null >&2) || $(emgr -l -L IV74246 2>/dev/null >&2) )    
    then
        #
        :   LVM efix installed which makes timestamp update unnecessary
        #
        return 0
    fi

    #
    :   Each of the V, R, M and F fields are padded to fixed length,
    :   to allow reliable comparisons.  E.g., maximum VRMF is
    :   99.99.999.999
    #
    typeset -li V R M F
    typeset -Z2 V                       # two digit version
    typeset -Z2 R                       # two digit release
    typeset -Z3 M                       # three digit modification
    typeset -Z3 F                       # three digit fix
    typeset -li lvm_lvl6=601008015      # minimum lvm level needed for 
                                        # automatic timestamp update
    typeset -li lvm_lvl7=701003046      # minimum lvl level, AIX 7
    typeset -li VRMF=0

    #
    :   Here try and figure out what level of LVM is installed
    #
    lslpp -lcqOr bos.rte.lvm | cut -f3 -d':' | IFS=. read V R M F
    VRMF=$V$R$M$F                       # get the LVM level

    if (( $V == 6 && $VRMF >= $lvm_lvl6 )) ||
       (( $VRMF >= $lvm_lvl7 ))
    then
        #
        :    LVM at a level in which timestamp update is unnecessary
        #
        return 0
    fi
    ################################################################################
fi

found_new_ts=""

#
:   Try to update the volume group ODM time stamp on every other node
:   in the resource group that owns $vg_name
#
if [[ -z $node_list ]]
then
    #
    :   We were not given a node list.  The node list is derived from
    :   the resource group that the volume group is in.
    #
    group_name=$(/usr/es/sbin/cluster/utilities/clodmget -q "name like *VOLUME_GROUP and value = $vg_name" -f group -n HACMPresource)
    if [[ -n $group_name ]]
    then
        #
        :   Find all other cluster nodes in the resource group that owns
        :   the volume group $vg_name
        #
        node_list=$(/usr/es/sbin/cluster/utilities/clodmget -q "group = $group_name" -f nodes -n HACMPgroup)
    fi
fi

#
:   Check to see if the volume group is known locally
#
if [[ -z $(odmget -q "name = $vg_name and  PdDvLn = logical_volume/vgsubclass/vgtype" CuDv) ]]
then
    #
    :	Volume group $vg_name is not defined on this node
    #
    if [[ -n $node_list ]]
    then
	#
	:   If the vg is not visible on the local node, then delegate
	:   this work to some other node in the node_list
	#
	LOCALNODENAME=${LOCALNODENAME:-$LOCAL_NODE}
	LOCALNODENAME=${LOCALNODENAME:-$(get_local_nodename 2> /dev/null)}
	if [[ -n $LOCALNODENAME ]]
	then
	    node_list=$(print "$node_list" | tr ' ' '\n' | tr ',' '\n' | grep -v -w -x $LOCALNODENAME | paste -s -d' ' -)
	fi
	if [[ -n $node_list ]]
	then
	    print -- "$node_list" | read node rest
	    /usr/es/sbin/cluster/sbin/cl_on_node -cspoc "-f -n $node" "/usr/es/sbin/cluster/events/utils/cl_update_vg_odm_ts $vg_name \"$node_list\""
	fi
    fi
    return 0
    #
    #	The astute reader will note that if this routine is
    #	called with no node list, for a volume group not known
    #	locally, no effort is made to check other nodes.
    #
fi

#
:   Get the vgid for volume group $vg_name
#
if ! vgid=$(getlvodm -v $vg_name)
then
    return 2            #   Cannot get volume group VGID from ODM
fi

#
:   Get the volume group timestamp for $vg_name
:   as currently saved in ODM
#
if ! current_odm_ts=$(getlvodm -T $vgid)
then
    return 3            #   Cannot get volume group time stamp from ODM                
fi

if [[ $o_flag != "TRUE" ]]
then
    typeset -E24 E_current_odm_ts	    # digits for significance
    typeset -E24 E_disk_ts		    # digits for significance

    #
    :   We only have to check the volume group time stamps against
    :   the disk time stamps if the volume group is not currently 
    :   on line.
    #
    if ! lsvg -o -L | grep -x -q -w $vg_name
    then
        #
        :   Volume group $vg_name is not on line
        #

        #
        :   Examine all the disk in volume group $vg_name
        :   looking for one with a timestamp different from
        :   what is currently in ODM
        #
        for vg_disk in $(lspv_in_vg $vg_name)
        do
          if disk_ts=$(lqueryvg -Tp $vg_disk)
          then
              if [[ $disk_ts != $current_odm_ts ]]
              then
                  #
                  :   Turn the timestamps into large positive integers, 
                  :   since these are 'ticks since epoch'.
                  #
                  E_disk_ts=16#0${disk_ts}
                  (( $E_disk_ts < 0 )) && (( E_disk_ts = - $E_disk_ts ))
                  E_current_odm_ts=16#0${current_odm_ts}
                  (( $E_current_odm_ts < 0 )) && (( E_current_odm_ts = - $E_current_odm_ts ))
                  if (( $E_disk_ts > $E_current_odm_ts ))
                  then
                      #
                      :  Disk $vg_disk has a larger - more recent - time 
                      :  stamp than the ODM timestamp for $vg_name
                      #
                      current_odm_ts=$disk_ts
                      found_new_ts="true"
                  fi
              fi
          fi
        done

        if [[ -n $found_new_ts ]]
        then
            # 
            :   Update CuAt, and the copy in the boot image for the local node
            #
            putlvodm -T $current_odm_ts $vgid && /usr/sbin/savebase > /dev/null
        fi
    fi
fi
#
:   Is an update necessary?
#
if [[ -n $node_list ]]
then
    LOCALNODENAME=${LOCALNODENAME:-$LOCAL_NODE}
    LOCALNODENAME=${LOCALNODENAME:-$(get_local_nodename 2> /dev/null)}
    if [[ -n $LOCALNODENAME ]]
    then
	#
	:   Skip the local node, since we have done that above.
	#
        node_list=$(print "$node_list" | tr ' ' '\n' | tr ',' '\n' | grep -v -w -x $LOCALNODENAME | paste -s -d, -)
    else
	#
	:   Make sure we have a comma separated list
	#
        node_list=$(print "$node_list" | tr ' ' '\n' | tr ',' '\n' | paste -s -d, -)
    fi
    #
    :   Update the time stamp on all those other nodes on which the
    :   volume group is currently varied off.  LVM will take care of
    :   the others.
    #
    if [[ -n $node_list ]]
    then
        _CSPOC_CALLED_FROM_SMIT=true cl_on_node -cspoc "-f -n $node_list" "lsvg -o | grep -qx $vg_name || /usr/sbin/putlvodm -T $current_odm_ts $vgid && /usr/sbin/savebase > /dev/null"
    fi
fi

return 0
