#!/bin/ksh93
# @(#)  7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_nova.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
#  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                                                      
#                                                                              

#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================

# Start of POD-formatted documentation. Viewing suggestions:
#      perldoc <FILENAME>
#      pod2text -c <FILENAME>
#      pod2text -c --code <FILENAME>
#      pod2html <FILENAME>
function devDoc {
 : <<'=cut' >/dev/null 2>&1

=head1 NAME

 KLIB_HACMP_modify_nova

=head1 SYNOPSIS

 clmgr modify nova [NOVALINK] \
 [ TIMEOUT=<###> ] \
 [ RETRY_COUNT=<###> ] \
 [ RETRY_DELAY=<###> ] \
 [ USER_NAME=<###> ]

=head1 DESCRIPTION

 Attempts to modify the specified NovaLink object within the PowerHA SystemMirror
 configuration.
 When modifying a NovaLink into PowerHA SystemMirror configuration, it can be associated with nodes. 
 Each node will try to communicate with its own NovaLink to perform Resource
 Optimized High Availability operations.
 
=head1 ARGUMENTS

 1. properties [REQUIRED] [hash ref]
 An associative array within which data about the
 created object can be returned to the caller.

 2. NovaLink [REQUIRED] [string]
 Host Name or IP address for the NovaLink.
 IPv4 and IPv6 format address are supported.

 3. TIMEOUT [OPTIONAL] [int]
 Timeout set on NovaLink operations.
 This value is expressed in minutes.
 The default TIMEOUT value is 10.

 4. RETRY_COUNT [OPTIONAL] [int]
 Number of retries set on NovaLink operations.
 The NovaLink operation which gets times out then will be retried this number of times. 
 The default RETRY_COUNT value is 5.

 5. RETRY_DELAY [OPTIONAL] [int]
 Duration of delay between two retries set on NovaLink operations.
 This value is expressed in [seconds]. 
 The NovaLink operation which gets times out, then will be retried 'RETRY_COUNT'number of times, with 'RETRY_DELAY' seconds between each retry. 
 The default value is 10.

 6. USER_NAME [OPTIONAL] [string]
 User name for NovaLink. 
 This USER_NAME option is mandatory for communication with NovaLink.
  
 7. PASSWORD [OPTIONAL] [string]
 Password for NovaLink.
 This PASSWORD option is not mandatory for SSH based communication with NovaLink.

=head1 CONFIGURATION/SETUP

1. If necessary, generate the SSH keys for your AIX node:

 1. cd ~/.ssh/
 2. ssh-keygen -t rsa

 This will create the private key (id_rsa) and public key (id_rsa.pub).

2. Add your nodes public key to the NovaLink SSH "allow" list:

 1. scp USER_NAME@<NovaLink>:.ssh/authorized_keys2 /tmp/NOVA_PUB_KEYS
 2. cat ~/.ssh/id_rsa.pub >> /tmp/NOVA_PUB_KEYS
 3. scp /tmp/NOVA_PUB_KEYS USER_NAME@<NovaLink>:.ssh/authorized_keys2
 4. rm -f /tmp/NOVA_PUB_KEYS
 5. Test it (i.e. ssh USER_NAME@<NOVA> date). No password should be required.

=head1 RETURN

 0: no errors were detected; the operation appears to have been successful
 1: a general error has occurred
 2: a specified resource does not exist, or could not be found
 3: some required input was missing
 4: some detected input was incorrect in some way
 5: a required dependency does not exist
 6: a specified search failed to match any data

=cut
} # End of POD-formatted documentation.



function KLIB_HACMP_modify_nova {
    LINENO=2 . $HALIBROOT/log_entry "$0()" "$CL"
    : INPUTS: $*

    typeset -n properties=$1
    typeset nova_label=${2//\"/}
    typeset timeout=${3//\"/}
    typeset retry_count=${4//\"/}
    typeset retry_delay=${5//\"/}
    typeset username=${6//\"/}
    typeset password=${7//\"/}

    [[ $CLMGR_LOGGING == 'med' ]] && set +x  # Only trace param values

    #===================================
    : Declare and initialize variables
    #===================================
    typeset -i CHECK_NOVA_ERROR=
    typeset -i rc=$RC_UNKNOWN
    typeset -i checkRC=$RC_SUCCESS

    #================================================================
    : Check for a defined cluster. No need to continue without one.
    #================================================================
    CL=$LINENO isClusterDefined
    if (( $? != RC_SUCCESS )); then
        rc=$RC_MISSING_DEPENDENCY
    fi

    #=================
    : Validate input
    #=================
    # nova_label
    typeset NOVA_LABEL=
    if [[ -z $nova_label ]]; then
        CL=$LINENO dspmsg -s $CLMGR_SET $CLMGR_MSGS 100 "\nERROR: an hostname or an IP address must be provided.\n\n" 1>&2
        rc=$RC_MISSING_INPUT
    else
        CL=$LINENO KLIB_HACMP_is_known_nova nova_label
        if (( $? != RC_SUCCESS )); then
            CL=$LINENO dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$nova_label" 1>&2
            dspmsg -s $CLMGR_SET $CLMGR_MSGS 1146 "Available NovaLinks:\n\n" 1>&2

            typeset available
            CL=$LINENO KLIB_HACMP_list_novas available
            for (( i=0; i<${#available[*]}; i++ )); do
                        if [[ ${available[$i]} != *([[:space:]]) ]]; then
                            print -u2 "\t${available[$i]}"
                        fi
            done
            print -u2 ""
            rc=$RC_NOT_FOUND
        else
            NOVA_LABEL=$nova_label
        fi
    fi

    typeset -i CONN_TYPE=
    CONN_TYPE=$(clodmget -f connection_type HACMPnovaparam)

    if (( $rc == RC_UNKNOWN )); then

        #===================
        : username parameter
        #===================
        typeset USER_NAME=
        if [[ -n $username ]]; then
            if [[ $username == [\-\+\~\@]* ]]; then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 103 \
'\nERROR: one or more invalid characters were detected in "%1$s":  "%2$s".\n\n' NAME "[-+~@]" 1>&2
                rc=$RC_INCORRECT_INPUT
            else
                USER_NAME=$username
            fi
        fi

        #===================
        : password parameter
        #===================
        typeset PASSWORD=
        if [[ -n $password ]]; then
            PASSWORD=$(print $password | clencodearg)
        fi

        if (( $CONN_TYPE == 0 )); then
            if [[ -n $password ]]; then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 1148 \
"\nWARNING: Specified PASSWORD will not be used for NovaLink connection type \"ssh\".\n\n" 1>&2
            fi
        fi

        #=========================
        : timeout parameter
        #=========================
        typeset TIMEOUT=
        if [[ -n $timeout ]]; then
            if [[ $timeout == "-1" ]]; then
                TIMEOUT=-1
            elif [[ $timeout != +([[:digit:]]) ]];  then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 809 "\nERROR: one or more invalid characters were detected in \"%1\$s\" (\"%2\$s\").\n\nValid input include either \"-1\" or a positive integer value.\n\n" "$timeout" "[-1|[0-9]*}" 1>&2
                rc=$RC_INCORRECT_INPUT
            else
                TIMEOUT=$timeout
            fi
        fi

        #=========================
        : retry count parameter
        #=========================
        typeset RETRY_COUNT=
        if [[ -n $retry_count ]]; then
            if [[ $retry_count == "-1" ]]; then
                RETRY_COUNT=-1
            elif [[ $retry_count != +([[:digit:]]) ]] then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 809 "\nERROR: one or more invalid characters were detected in \"%1\$s\" (\"%2\$s\").\n\nValid input include either \"-1\" value or a positive integer value.\n\n" "$timeout" "[-1|[0-9]*}" 1>&2
                rc=$RC_INCORRECT_INPUT
            else
                RETRY_COUNT=$retry_count
            fi
        fi

        #=========================
        : retry delay parameter
        #=========================
        typeset RETRY_DELAY=
        if [[ -n $retry_delay ]]; then
            if [[ $retry_delay == "-1" ]]; then
                RETRY_DELAY=-1
            elif [[ $retry_delay != +([[:digit:]]) ]] then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 809 "\nERROR: one or more invalid characters were detected in \"%1\$s\" (\"%2\$s\").\n\nValid input include either \"-1\" value or a positive integer value.\n\n" "$timeout" "[-1|[0-9]*}" 1>&2
                rc=$RC_INCORRECT_INPUT
            else
                RETRY_DELAY=$retry_delay
            fi
        fi

        if [[ -z $username ]]; then
            print -- "clodmget -q name=$NOVA_LABEL -f user -n HACMPnova" >>$CLMGR_TMPLOG
            USER_NAME=$(clodmget -q name=$NOVA_LABEL -f user -n HACMPnova)
            print -- "clodmget -q name=$NOVA_LABEL -f user -n HACMPnova rc=$? USER_NAME=$USER_NAME" >>$CLMGR_TMPLOG
        fi

    fi

    if (( $rc == RC_UNKNOWN )); then
        #===================================================================================================================
        : This NovaLink should be reachable and password less SSH communication should work from the local node. 
        :  Get associated managed system for this NovaLink and build the list of nodes from this managed system.
        :  If any error during the connectivity check, just break unless we  ask to force.
        #===================================================================================================================
        typeset NODES= managed_system= nodelist= nova_cmd=
        print -- "ssh -l $USER_NAME -o BatchMode=yes -o ConnectTimeout=3 $NOVA_LABEL date" >>$CLMGR_TMPLOG
        ssh -l $USER_NAME -o BatchMode=yes -o ConnectTimeout=3 $NOVA_LABEL date >>$CLMGR_TMPLOG 2>&1
        if (( $? == RC_SUCCESS )); then
            nova_cmd="pvmctl sys list --hide-label -d mtms_str"
            print -- "$0()[$LINENO]($SECONDS): ssh -l $USER_NAME -o BatchMode=yes -o ConnectTimeout=3 $NOVA_LABEL $nova_cmd" >>$CLMGR_TMPLOG # Always log commands
            managed_system=$(ssh -l $USER_NAME -o BatchMode=yes -o ConnectTimeout=3 $NOVA_LABEL $nova_cmd)
            checkRC=$?
            print -- "$0()[$LINENO]($SECONDS): ssh -l $USER_NAME -o BatchMode=yes -o ConnectTimeout=3 $NOVA_LABEL $nova_cmd rc=$checkRC" >>$CLMGR_TMPLOG # Always log commands
            if (( $checkRC != RC_SUCCESS )) || [[ -z $managed_system ]]; then
                CL=$LINENO dspmsg -s $CLMGR_SET $CLMGR_MSGS 1164 "\nERROR: failed to get managed system for NovaLink \"%1\$s\".\n\n" "$NOVA_LABEL" 1>&2
                rc=$RC_ERROR
            fi
        else
            cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1165 "\nERROR: could not communicate with NovaLink \"%1\$s\" via SSH from local node. Check \"%1\$s\" is valid. Check the public key for local node installed correctly on \"%1\$s\". Check for any network issues or name resolution problems or firewall problems.\n" "$NOVA_LABEL" 1>&2
            rc=$RC_ERROR
        fi

        if (( $rc == RC_UNKNOWN )); then
            for node in $(clnodename); do
                print -- "$0()[$LINENO]($SECONDS): cl_dynresop -n "${node%%\.*}" -C 2>/dev/null" >>$CLMGR_TMPLOG # Always log commands
                if [[ $managed_system == $(cl_dynresop -n "${node%%\.*}" -C 2>/dev/null) ]]; then
                    nodelist="${nodelist:+$nodelist }${node%%\.*}"
                fi
            done

        fi
        if [[ -n $nodelist ]]; then
            if (( $rc == RC_UNKNOWN )); then
                for node in $nodelist; do
                    print -- "check_nova_connectivity_with_node $node $NOVA_LABEL NODES=$NODES" >>$CLMGR_TMPLOG
                    check_nova_connectivity_with_node $node $NOVA_LABEL NODES $USER_NAME $PASSWORD
                    checkRC=$?
                    print -- "check_nova_connectivity_with_node $node $NOVA_LABEL NODES=$NODES rc=$checkRC" >>$CLMGR_TMPLOG
                    if (( $checkRC != 0 )); then
                        CHECK_NOVA_ERROR=1
                        break
                    fi
                done
            fi
        fi
    fi

    if (( $rc == RC_UNKNOWN )); then
        #==========================================================
        : Define the NOVA if no input errors have been detected
        #==========================================================

        if (( $CHECK_NOVA_ERROR != 1 )); then
            #==========================================================
            : Define the NOVA if no connectivity errors have been detected
            #==========================================================

            #==========================================================
            : Firstly, update the NOVA object
            #==========================================================
            typeset nOpt= tOpt= rOpt= dOpt= uOpt= pOpt=
            [[ -z $NOVA_LABEL ]]   && nOpt=" " || nOpt=" -n $NOVA_LABEL"
            [[ -z $TIMEOUT ]]     && tOpt=" " || tOpt=" -t $TIMEOUT"
            [[ -z $RETRY_COUNT ]] && rOpt=" " || rOpt=" -c $RETRY_COUNT"
            [[ -z $RETRY_DELAY ]] && dOpt=" " || dOpt=" -d $RETRY_DELAY"
            [[ -z $username ]] && uOpt=" " || uOpt=" -u $username"
            [[ -z $password ]] && pOpt=" " || pOpt=" -p $PASSWORD"
            mopt=" -m $managed_system"

            print -- "$0()[$LINENO]($SECONDS): clchnova $nOpt$tOpt$rOpt$dOpt$uOpt$pOpt" >>$CLMGR_TMPLOG # Always log command
            clchnova $nOpt$tOpt$rOpt$dOpt$uOpt$pOpt
            rc=$?
            print -- "$0()[$LINENO]($SECONDS): clchnova $nOpt$tOpt$rOpt$dOpt$uOpt$pOpt rc=$rc" >>$CLMGR_TMPLOG # Always log command result

            if (( $rc != RC_SUCCESS )); then
                CL=$LINENO dspmsg -s $CLMGR_SET $CLMGR_MSGS 201 "\nERROR: failed to modify \"%1\$s\".\n\n" "$NOVA_LABEL" 1>&2
                rc=$RC_ERROR
            else
                #==========================================================
                : Now update the nodes objects
                :  - For the nodes given in parameter one per one, i.e we loop around the nodes
                :  -- we look to see if the nova is already here or if it must be added
                :  - For all other nodes, .i.e all nodes not given in parameter
                :  -- we must remove the nova if it was there
                #==========================================================

                if [[ -n $NODES ]]; then
                    #==========================================================
                    :  - for the nodes given in parameter one per one, i.e. we loop around the nodes
                    :  -- we look to see if the nova is already here or if it must be added
                    #==========================================================
                    for NODE in $NODES; do
                        typeset NOpt= kvOpt=

                        kvOpt="-c NOVA_MANAGED_SYSTEM=$managed_system"
                        NOpt=" -n $NODE"
                        print -- "$0()[$LINENO]($SECONDS): clchnovaparam $NOpt $kvOpt" >>$CLMGR_TMPLOG
                        clchnovaparam $NOpt $kvOpt
                        rc=$?
                        print -- "$0()[$LINENO]($SECONDS): clchnovaparam $NOpt $kvOpt rc=$rc" >>$CLMGR_TMPLOG # Always log command result
                        if (( $rc != RC_SUCCESS )); then
                            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1144 "\nERROR: failed to associate \"%1\$s\" NODES and \"%2\$s\" Managed system.\n\n" "$NODE" "$managed_sys_name" 1>&2
                            rc=$RC_ERROR
                            break
                        fi
                    done
                fi

                #=================================
                : If output from this operation was requested, retrieve it
                #=================================
                if (( $rc == RC_SUCCESS )); then
                    if (( $CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then
                        CL=$LINENO KLIB_HACMP_get_nova_attributes "$NOVA_LABEL" properties
                    fi
                fi
            fi
        else
            rc=$RC_INCORRECT_INPUT
        fi
    fi

    #=================================
    : If a user input error was detected, provide some helpful suggestions
    #=================================
    if (( $rc == RC_MISSING_INPUT || $rc == RC_INCORRECT_INPUT )) && \
        [[ $CLMGR_GUI == *([[:space:]]) ]]; then
        CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 104 "For more information about available options and syntax, try\n\"$HAUTILS/clmgr %1\$s\". As an\nalternative, if the PowerHA SystemMirror man pages have been installed, invoke\n\"$HAUTILS/clmgr -hv\" (or \"/usr/bin/man clmgr\"),\nsearching for \"%2\$s\" in the displayed text.\n\n" "modify nova -h" "NOVA:" 1>&2
    fi

    log_return_msg "$rc" "$0()" "$LINENO"
    return $?
}
# End of "KLIB_HACMP_modify_nova()"
