#!/bin/ksh93 # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2018,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/acquire_service_addr.sh 1.74.1.5 # # Licensed Materials - Property of IBM # # COPYRIGHT International Business Machines Corp. 1990,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/acquire_service_addr.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM ######################################################################### # # Name: acquire_service_addr # # Description: This script is called when the local node joins the # cluster or a remote node leaves the cluster and # does the initial process of identifying where any service # IP addressed need to be acquired. # # Arguments: service address, if called for serial processing, otherwise # none # # Returns: 0 success # 1 fatal error # 2 bad argument # 11 recoverable error # ######################################################################### ######################################################################### # # Name: get_list_head and get_list_tail # # Description: utility functions to pull items from the head or tail # of a colon delimited list # # Inputs: the list to work on # # Outputs: head or tail list of items # # Returns: none # ######################################################################### function get_list_head { echo $* | cut -f 1 -d : | sed 's/,/ /g' |read LIST print $LIST } # End of "get_list_head()" function get_list_tail { case $* in *:* ) echo $* | cut -f 2- -d : |read LIST print $LIST return ;; * ) echo "" ;; esac } # End of "get_list_tail()" ######################################################################### # # Name: best_boot_addr # # This routine finds the best boot interface for hosting an aliased service # address. This routine exercises the resource distribution preference for # service labels. The available options are: # anti-collocation - the default - all UP interfaces are sorted # according to the number of addresses currently on the interface. # The interface with the least number is selected. # collocation - put all service on the same interface # collocation with persistent - put all service on the same interface # as the one holding the persistent # anti-collocation with persistent - avoid putting service on the # same interface as the persistent # # Arguments: network name # List of candidate boot addresses on that network # # Returns: network address of the selected boot interface # ######################################################################### function best_boot_addr { typeset best_candidate=NONE typeset best_aliases=0 typeset ip_family="" service="" services="" typeset MA="" [[ $VERBOSE_LOGGING == "high" ]] && set -x typeset NETWORK=$1 shift typeset candidate_boots=$* # if there is only one boot then thats the candidate - regardless of # state or distribution preference integer num_candidates=$(echo $candidate_boots | tr " " "\n" | wc -l) if (( $num_candidates == 1 )); then echo $candidate_boots return fi # find the (optional) service label distribution ppreference for this # network MA=$(odmget -q"network = $NETWORK AND function = shared" HACMPadapter |\ grep "max_aliases" | awk '{print $3}' | sort -nu | tail -1) # decode the setting case $MA in 1|771 ) # simple collocation # if there is already a service on any of the candidates, then # that is the candidate for this service # find all services on this network services=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "service" && $3 == NET) print $1}' | sort) service_if="" for service in $services do # is it on this node ? service_if=$(LC_ALL=C clgetif -a $service 2>/dev/null | cut -f1) [[ -n "$service_if" ]] && break #found it done # if there is a service, scan list of candidates if [[ -n "$service_if" ]] then for candidate in $candidate_boots do boot_if=$(LC_ALL=C clgetif -a $candidate 2>/dev/null | cut -f1) if [[ -n "$boot_if" && $boot_if == $service_if ]] then best_candidate=$candidate break fi done fi # if the loop above did not identify a candidate, then the # candidate is the first UP boot if [[ $best_candidate == "NONE" ]]; then for candidate in $candidate_boots do LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | cut -f7,15 -d"$OP_SEP" | IFS="$OP_SEP" read candidate_dot_addr ip_family # find the state of this candidate if [[ $ip_family == "AF_INET" ]]; then addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi candidate_state=$(eval print $addr) if [[ $candidate_state == "UP" ]]; then best_candidate=$candidate break # all done fi done fi ;; 259|1283) # collocation with persistent # if there is a persistent label on any of the candidates, then # that is the candidate for this service persistent=$(cllsif -J "$OP_SEP" -Sp $LOCALNODENAME | awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "persistent" && $3 == NET) print $1}' | sort) persistent_if="" if [[ -n "$persistent" ]] then # is it on this node ? persistent_if=$(LC_ALL=C clgetif -a $persistent 2>/dev/null | cut -f1) fi # if there is a persistent, scan list of candidates if [[ -n "$persistent_if" ]] then # Find any service labels already present on this node LC_ALL=C clgetif -a $(cllssvcs 2>/dev/null | cut -f1) 2>/dev/null | read ALIVE_SERV_IF for candidate in $candidate_boots do LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | \ cut -f7,15 -d"$OP_SEP" | IFS="$OP_SEP" read candidate_dot_addr ip_family # find the state of this candidate if [[ $ip_family == "AF_INET" ]]; then addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi candidate_state=$(eval print $addr) boot_if=$(LC_ALL=C clgetif -a $candidate 2>/dev/null | cut -f1) # If the interface has any other service or # persistent label and the interface is UP, then its our # best candidate if [[ $candidate_state == "UP" && -n $boot_if && \ ( $boot_if == $persistent_if || \ $boot_if == $ALIVE_SERV_IF ) ]] then best_candidate=$candidate break fi done fi # if the loop above did not identify a candidate, then go through # the same calculation as we use for simple anti-collocation if [[ $best_candidate == "NONE" ]]; then for candidate in $candidate_boots do LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | cut -f7,15 -d"$OP_SEP" | IFS="$OP_SEP" read candidate_dot_addr ip_family # find the state of this candidate if [[ $ip_family == "AF_INET" ]]; then addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi candidate_state=$(eval print $addr) if [[ $candidate_state == "UP" ]]; then # this interface is UP - now lets check how many # addresses it is already hosting candidate_if=$(LC_ALL=C clgetif -a $candidate_dot_addr 2>/dev/null | cut -f1) candidate_aliases=$(LC_ALL=C ifconfig $candidate_if | grep -c -w "inet[6]\{0,1\}") if [[ $best_candidate == "NONE" ]] || \ (( $candidate_aliases < $best_aliases )) then best_candidate=$candidate best_aliases=$candidate_aliases fi fi done fi ;; 515|1539 ) # anti-collocation with persistent # if there is a persistent label on any of the candidates, then # that candidate should be marked DOWN to avoid its selection persistent=$(cllsif -J "$OP_SEP" -Sp $LOCALNODENAME | awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "persistent" && $3 == NET) print $1}' | sort) save_if="NONE" persistent_if="" if [[ -n "$persistent" ]] then # is it on this node ? persistent_if=$(LC_ALL=C clgetif -a $persistent 2>/dev/null | cut -f1) fi # if there is a persistent, scan list of candidates if [[ -n "$persistent_if" ]] then for candidate in $candidate_boots do boot_if=$(LC_ALL=C clgetif -a $candidate 2>/dev/null | cut -f1) if [[ -n $boot_if && $boot_if == $persistent_if ]] then LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | cut -f7,15 -d"$OP_SEP" | IFS="$OP_SEP" read candidate_dot_addr ip_family # find the state of this candidate if [[ $ip_family == "AF_INET" ]]; then addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi candidate_state=$(eval print $addr) # if the interface is up, save it away just in case # its our only up interface [[ $candidate_state == "UP" ]] && save_if=$candidate_dot_addr # set state to down if [[ $ip_family == "AF_INET" ]]; then addr=i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi export $addr="DOWN" break fi done fi # now that any interface holding the persistent is marked as DOWN, # go through the same calculation as we use for simple # anti-collocation for candidate in $candidate_boots do LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | cut -f7,15 -d"$OP_SEP" | IFS="$OP_SEP" read candidate_dot_addr ip_family # find the state of this candidate if [[ $ip_family == "AF_INET" ]]; then addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi candidate_state=$(eval print $addr) if [[ $candidate_state == "UP" ]]; then # this interface is UP - now lets check how many addresses # it is already hosting candidate_if=$(LC_ALL=C clgetif -a $candidate_dot_addr 2>/dev/null | cut -f1) candidate_aliases=$(LC_ALL=C ifconfig $candidate_if | grep -c -w "inet[6]\{0,1\}") if [[ $best_candidate == "NONE" ]] || \ (( $candidate_aliases < $best_aliases )) then best_candidate=$candidate best_aliases=$candidate_aliases fi fi done # if the loop above did not find a candidate then we cannot # exercise the preference - try setting the candidate to the # same interface as has the persistent [[ $best_candidate == "NONE" ]] && best_candidate=$save_if ;; * ) # default to rdp_anti_collocation # test all the candidates in the list for candidate in $candidate_boots do LC_ALL=C cllsif -J "$OP_SEP" -Sn $candidate | cut -f7,15 -d"$OP_SEP" | IFS="$OP_SEP" read candidate_dot_addr ip_family # find the state of this candidate if [[ $ip_family == "AF_INET" ]]; then addr=\$i${candidate_dot_addr//\./x}_${LOCALNODENAME//-/$HA_DASH_CHAR} else addr=\$i${candidate_dot_addr//:/y}_${LOCALNODENAME//-/$HA_DASH_CHAR} fi candidate_state=$(eval print $addr) if [[ $candidate_state == "UP" ]]; then # this interface is UP - now lets check how many addresses # it is already hosting candidate_if=$(LC_ALL=C clgetif -a $candidate_dot_addr 2>/dev/null | cut -f1) candidate_aliases=$(LC_ALL=C ifconfig $candidate_if | grep -c -w "inet[6]\{0,1\}") if [[ $best_candidate == "NONE" ]] || \ (( $candidate_aliases < $best_aliases )) then best_candidate=$candidate best_aliases=$candidate_aliases fi fi done ;; esac # once here, the best candidate should have been selected if [[ "$best_candidate" != "NONE" ]]; then echo $best_candidate return fi # Should never get here dspmsg scripts.cat 342 "Unable to determine local boot/service interface.\n" exit 1 } # End of "best_boot_addr()" ######################################################################### # # MAIN Main main # ######################################################################### PROGNAME=${0##*/} export PATH="$(/usr/es/sbin/cluster/utilities/cl_get_path all)" OP_SEP="$(cl_get_path -S)" # these variable control the telinit wait loop TELINIT=false TELINIT_FILE="/usr/es/sbin/cluster/.telinit" # try this number of times typeset -i telinit_wait_count=36 # waiting this much between tries DELAY=5 # by default produces a wait of 3 minutes for telinit to complete STATUS=0 PROC_RES=false ALLSRVADDRS="All_service_addrs" ALLNOERRSRV="All_nonerror_service_addrs" # # Turn tracing on after initialization # if [[ $VERBOSE_LOGGING == "high" ]]; then set -x version='1.74.1.5' fi # # if JOB_TYPE is set, and it doesn't equal to "GROUP", then # we are processing for process_resources # if [[ ${JOB_TYPE:-0} != 0 && $JOB_TYPE != "GROUP" ]]; then PROC_RES=true else # check arguments for serial case only. Otherwise everything comes # from the environment. if (( $# <= 0 )) then cl_echo 1028 "Usage: $PROGNAME service_address\n" $PROGNAME exit 2 fi export RESOURCE_GROUPS=$GROUPNAME fi # # Change NSORDER to avoid hangs due to NIS # saveNSORDER=${NSORDER:-UNDEFINED} NSORDER=local export NSORDER # update the resource manager with this operation cl_RMupdate resource_acquiring $ALLSRVADDRS $PROGNAME # # go through all resource groups # for GROUPNAME in $RESOURCE_GROUPS; do export GROUPNAME # # if called from process_resources, the list will be in the env, otherwise # the list is passed as en axplicit arg # if [[ $PROC_RES == true ]]; then get_list_head $IP_LABELS | read SERVICELABELS get_list_tail $IP_LABELS | read IP_LABELS else SERVICELABELS=$* fi for service in $SERVICELABELS do # # Determine if address is already configured. If not, try to # acquire it. # LC_ALL=C clgetif -a $service 2>/dev/null if (( $? != 0 )) then # Get the list of boot addresses on this node which are on the same # network as the service address NETWORK=$(cllsif -J "$OP_SEP" -Sn $service | cut -d"$OP_SEP" -f3 | uniq) boot_list=$(cllsif -J "$OP_SEP" -Si $LOCALNODENAME | awk -F"$OP_SEP" -v NET="$NETWORK" '{if ($2 == "boot" && $3 == NET) print $1}' | sort) if [[ -z "$boot_list" ]] then # # If this node has no boot addresses on this network - it # cannot host the service address # continue fi # # now find the best candidate out of the list # boot_addr=$(best_boot_addr $NETWORK $boot_list) if (( $? != 0 )) then echo "$PROGNAME: Could not find any active boot adapter in network $NETWORK on node $LOCALNODENAME\n" cl_RMupdate resource_error $service $PROGNAME if [[ $PROC_RES == true ]]; then STATUS=11 else STATUS=1 fi continue fi INTERFACE=$(LC_ALL=C clgetif -a $boot_addr 2>/dev/null | cut -f1) # get the interface and ip of the boot cllsif -J "$OP_SEP" -Sn $boot_addr | cut -f7,9 -d"$OP_SEP" | IFS="$OP_SEP" read boot_dot_addr INTERFACE if [[ -z "$INTERFACE" ]] then echo "$PROGNAME: Could not find interface name for boot adapter $boot_addr\n" cl_RMupdate resource_error $service $PROGNAME if [[ $PROC_RES == true ]]; then STATUS=11 continue else STATUS=1 fi else # We have a boot interface defined. Get netmask for the service # (which can be different from the boot) and the address then # call swap ip address to do the actual work cllsif -J "$OP_SEP" -Sn $service | cut -f7,11,15 -d"$OP_SEP" | uniq | IFS="$OP_SEP" read service_dot_addr NETMASK INET_FAMILY if [[ $INET_FAMILY == "AF_INET6" ]] then cl_swap_IPv6_address rotating acquire $INTERFACE $service_dot_addr $boot_dot_addr else cl_swap_IP_address rotating acquire $INTERFACE $service_dot_addr $boot_dot_addr $NETMASK fi # Check the return code. RC=$? if (( $RC != 0 )) then if [[ $PROC_RES == false ]]; then STATUS=1 else # the error code has to be propagated to process_resources STATUS=$RC fi else if [[ $PROC_RES == false ]]; then STATUS=0 TELINIT=true fi fi fi # if INTERFACE is non-empty fi # if clgetif service successful done # for service in $SERVICELABELS # update the resource manager with the results cl_RMupdate resource_up $ALLNOERRSRV $PROGNAME done #for GROUPNAME if [[ $saveNSORDER != UNDEFINED ]]; then export NSORDER=$saveNSORDER else export NSORDER="" fi if [[ $PROC_RES == false ]]; then if [[ $TELINIT == true ]] then cl_telinit fi fi #endof PROC_RES exit $STATUS #============================================================================== # The following, comment block attempts to enforce coding standards when this # file is edited via emacs or vim. This block _must_ appear at the very end # of the file, or the editor will not find it, and it will be ignored. #============================================================================== # Local Variables: # indent-tabs-mode: nil # tab-width: 4 # End: #============================================================================== # vim: tabstop=4 shiftwidth=4 expandtab #==============================================================================