#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG                                                    
#  This is an automatically generated prolog.                                  
#                                                                              
#  Copyright (C) Altran ACT S.A.S. 2022.  All rights reserved.  
#                                                                              
#  ALTRAN_PROLOG_END_TAG                                                      
#                                                                              
# @(#)  16365cd 43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_cluster_cloudroha.sh, 61aha_r726, 2205H_aha726, Jun 16 2022 05:54 AM

#================================================
# The following, commented line enforces hmcing
# 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 --cloudroha <FILENAME>
#      pod2html <FILENAME>
function devDoc {
   : <<'=cut' >/dev/null 2>&1

=head1 NAME

 KLIB_HACMP_modify_cluster_cloudroha

=head1 SYNOPSIS

 clmgr manage cluster cloudroha \
             ACTION=<add/modify/delete> \
             AUTHKEY=<Cloud account apikey> \
             SERVICE=<Cloud region/zone identifier(CRN)> \
             [ CLOUDTYPE=IBM ] \
             [ TIMEOUT=## <in minutes> ] \
             [ CLOUDSITE=<PowerHA site name> ]
 NOTE: the alias for "cluster" is "cl".

=head1 DESCRIPTION

Attempts to modify the cluster NovaLink configuration.

=head1 ARGUMENTS

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

 2. ACTION [REQUIRED]
    Provide action to take with the supplied values.

 3. AUTHKEY [REQUIRED]
    This is authentication key of cloud account.

 4. SERVICE [REQUIRED]
    This is the compute service identifier where PowerVS is located.
    Based on this, POWERVS_INSTANCEIDs are fetched for all Cloud VMs
    located under this service.

 5. CLOUDTYPE [OPTIONAL]
    Choose cloud type where the PowerVS machine is hosted.
    Default value is IBM.

 6. TIMEOUT [OPTIONAL] [integer]
    Default timeout for Cloud operations is 5 minutes.
    This value is expressed in minutes.
    The supplied timeout is applicable to all PowerVS instances under cluster/site.

 7. CLOUDSITE [REQUIRED with condition]
    Provide PowerHA site name in case of site-based cluster.
    Optional for standard cluster (NSC) and ignored if provided.
    

=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_cluster_cloudroha {
    LINENO=2 . $HALIBROOT/log_entry "$0()" "$CL"
    : INPUTS: $*

    typeset -n properties=$1
    shift

    typeset user_input=$*
    typeset -l operation=${1//\"/}
    typeset apikey=${2//\"/}
    typeset crn=${3//\"/}
    typeset cloudtype=${4//\"/}
    typeset timeout=${5//\"/}
    typeset cloudsite=${6//\"/}

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

    #===================================
    : Declare and initialize variables
    #===================================
    typeset -i rc=$RC_UNKNOWN
    typeset -A clattrs
    typeset nodelist
    typeset action
    typeset oldargs=""
    typeset cmdargs=""
    typeset -i change_done=0

    CL=$LINENO KLIB_HACMP_get_cluster_attributes clattrs

    #================================================================
    : Check for a defined cluster. No need to continue without one.
    #================================================================
    if [[ -z ${clattrs[CLUSTER_NAME]} ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 35 "\nERROR: no cluster is defined yet.\n\n" 1>&2
        rc=$RC_MISSING_DEPENDENCY

    #=================
    : Validate input
    #=================
    elif [[ $user_input == *([[:space:]]) ]] ; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 401 "\nERROR: no valid modifications were specified for \"%1\$s\".\n\n" "$(cllsclstr -cS | /usr/bin/cut -d: -f2)" 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if (( $rc == RC_UNKNOWN )); then
        if [[ -z $operation ]]; then
            rc=$RC_MISSING_INPUT
        else 
            if [[ $operation != *([[:space:]]) ]]; then
                CL=$LINENO verify_in_set ACTION "$operation" "add modify change remove delete" operation
                (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT
            fi
            
            if [[ $operation == @(add|modify|change) ]] && [[ -z $apikey || -z $crn ]]; then
                rc=$RC_MISSING_INPUT
            fi 
        fi

        [[ -z $cloudtype ]] && cloudtype="IBM"  # Default value, if not provided
        if [[ $cloudtype != *([[:space:]]) ]]; then
            CL=$LINENO verify_in_set CLOUDTYPE "$cloudtype" "IBM" cloudtype
            (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT
        fi

        [[ -z $timeout ]] && timeout=5  # Default value, if not provided
        if [[ $timeout != +([[:digit:]]) ]] ; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 111 "\nERROR: \"%1\$s\" requires a positive, integer value.\n\n" TIMEOUT 1>&2
            rc=$RC_INCORRECT_INPUT
        fi

        #
        # CLOUDSITE option is mandatory for site-based cluster.
        # Optional for standard (NSC) cluster and ignored if provided.
        # This option is validated irrespective of ACTION.
        #
        if [[ ${clattrs[TYPE]} == "NSC" ]]; then
            [[ -n $cloudsite ]] && /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 1506 "\nINFO: \"%1\$s\" is optional for \"%2\$s\" cluster type. Hence, ignoring it and proceeding with cluster name.\n" CLOUDSITE NSC 1>&2

            print "$0()[$LINENO]($SECONDS): clnodename" >>$CLMGR_TMPLOG
            nodelist=$(clnodename 2>/dev/null)
            print "$0()[$LINENO]($SECONDS): cluster nodes == $nodelist" >>$CLMGR_TMPLOG
        else
            if [[ $cloudsite != *([[:space:]]) ]]; then
                CL=$LINENO KLIB_HACMP_is_known_site "$cloudsite" >/dev/null 2>&1
                (( $? != RC_SUCCESS )) && rc=$RC_NOT_FOUND
            fi

            if [[ -z $cloudsite ]]; then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 298 "\nERROR: a site must be specified.\n\n" 1>&2
                rc=$RC_MISSING_INPUT
            else
                if (( $rc == RC_NOT_FOUND )); then
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 '\nERROR: "%1$s" does not appear to exist!\n\n' "$cloudsite" 1>&2
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 157 "Available Sites:\n\n" 1>&2

                    typeset available
                    CL=$LINENO KLIB_HACMP_list_sites available
                    for (( i=0; i<${#available[*]}; i++ )); do
                        if [[ ${available[$i]} != *([[:space:]]) ]]; then
                            print -u2 "\t${available[$i]}"
                        fi
                    done
                    print -u2 ""
                else
                    print "$0()[$LINENO]($SECONDS): clodmget -q \"name=$cloudsite\" -n -f nodelist HACMPsite" >>$CLMGR_TMPLOG
                    nodelist=$(clodmget -q "name=$cloudsite" -f nodelist HACMPsite)
                    print "$0()[$LINENO]($SECONDS): clodmget RC: $?; $cloudsite nodes= $nodelist" >>$CLMGR_TMPLOG
                fi
            fi
        fi # end of CLOUDSITE validation

        if [[ -z $nodelist ]]; then
            dspmsg -s $CLMGR_SET $CLMGR_MSGS 1507 "\nERROR: Found empty node list for the cluster or site. Could not proceed with Cloud ROHA configuration.\n" 1>&2
            rc=$RC_MISSING_DEPENDENCY
        fi 
    fi
    
    #=======================================
    # Gather all the input values and submit 
    #=======================================
    if (( $rc == RC_UNKNOWN || $rc == RC_SUCCESS )); then
        # 
        # Check whether Cloud configuration is present
        #
        print "$0()[$LINENO]($SECONDS): cllspowervs -l" >>$CLMGR_TMPLOG
        typeset out=$(cllspowervs -l 2>/dev/null)
        print "$0()[$LINENO]($SECONDS): RC=$?; output=$out" >>$CLMGR_TMPLOG

        if [[ "$operation" == "add" ]]; then
            action="-a"
            if [[ -n "$out" ]]; then
                if [[ ${clattrs[TYPE]} == "NSC" ]]; then
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 851 "\nERROR: \"%1\$s\" is already configured for Resource Optimized High Availability services.\n\n" "Cluster ${clattrs[CLUSTER_NAME]}" 1>&2
                    rc=$RC_ERROR
                    return $rc
                else
                    if [[ -n $(echo $out | grep -w $cloudsite) ]]; then
                        dspmsg -s $CLMGR_SET $CLMGR_MSGS 851 "\nERROR: \"%1\$s\" is already configured for Resource Optimized High Availability services.\n\n" "Site $cloudsite" 1>&2
                        rc=$RC_ERROR
                        return $rc
                    fi
                fi
            fi
        else
            if [[ ${clattrs[TYPE]} == "NSC" ]]; then
                if [[ -z $out ]]; then
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 853 "\nERROR: \"%1\$s\" is not configured for Resource Optimized High Availability services.\n\n" "Cluster ${clattrs[CLUSTER_NAME]}" 1>&2
                    rc=$RC_ERROR
                    return $rc
                fi
            else
                if [[ -n $out ]] && [[ -z $(echo $out | grep -w $cloudsite) ]]; then
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 853 "\nERROR: \"%1\$s\" is not configured for Resource Optimized High Availability services.\n\n" "Site $cloudsite" 1>&2
                    rc=$RC_ERROR
                    return $rc
                fi
            fi

            if [[ "$operation" == @(modify|change) ]]; then
                action="-c"
            else
                action="-r"
            fi
        fi


        #
        # Now proceed with actual configuration change
        #
        if [[ $operation == @(add|modify|change) ]]; then

            [[ -n $apikey ]] && cmdargs="$cmdargs POWERVS_APIKEY=$apikey"
            [[ -n $crn ]] && cmdargs="$cmdargs POWERVS_CRN=$crn"
            [[ -n $cloudtype ]] && cmdargs="$cmdargs POWERVS_CLOUD=$cloudtype"
            [[ -n $timeout ]] && cmdargs="$cmdargs POWERVS_TIMEOUT=$timeout"

            # Take backup of current data; in case if new data addition fails, we can restore the config back
            if [[ $operation != "add" ]]; then
                # pick any single node from list
                typeset anynode=$(echo $nodelist | cut -f1 -d" ")
                print "$0()[$LINENO]($SECONDS): clodmget -q \"name=$anynode and object like POWERVS_*\" -n -d\"=\" -f object,value HACMPnode" >>$CLMGR_TMPLOG
                oldargs=$(clodmget -q "name=$anynode and object like POWERVS_*" -n -d"=" -f object,value HACMPnode)
                print "$0()[$LINENO]($SECONDS): clodmget RC: $?; oldargs= $oldargs" >>$CLMGR_TMPLOG
            fi

            #
            # Add to PowerHA configuration (HACMPnode ODM)
            #
            for node in $nodelist; do
                print "$0()[$LINENO]($SECONDS): /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node $cmdargs" >>$CLMGR_TMPLOG
                /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node $cmdargs
                rc=$?
                print "$0()[$LINENO]($SECONDS): clchpowervs RC: $rc" >>$CLMGR_TMPLOG
                if (( $rc != RC_SUCCESS )); then
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 855 "\nERROR: the attempt to modify the Resource Optimized High Availability settings for \"%1\$s\" has failed.\n\n" $node 1>&2
                    return $rc
                fi
            done

            #
            : Now perform connectivity test to cloud vm based on added apikey and crn values.
            : And, fetch cloud vm instance ids of all cluster/site nodes
            #
            print "$0()[$LINENO]($SECONDS): /usr/es/sbin/cluster/utilities/clcloudroha -o query -a pvm_id" >>$CLMGR_TMPLOG
            typeset insdata=$(/usr/es/sbin/cluster/utilities/clcloudroha -o 'query' -a 'pvm_id' 2>/dev/null)
            rc=$?
            print "$0()[$LINENO]($SECONDS): clcloudroha RC:$rc; insdata=$insdata" >>$CLMGR_TMPLOG

            if [[ -n "$insdata" ]] && (( $rc == $RC_SUCCESS )); then
                #
                # Cloud Connectivity success; Add the cloud vm Instance IDs to the PowerHA configuration
                #
                for node in $nodelist; do
                    typeset insid=$(echo "$insdata" | grep -w $node | cut -d" " -f2)
                    print "$0()[$LINENO]($SECONDS): /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node POWERVS_INSTANCEID=$insid" >>$CLMGR_TMPLOG
                    /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node POWERVS_INSTANCEID=$insid
                    (( rc |= $? ))
                    print "$0()[$LINENO]($SECONDS): clchpowervs RC: $rc" >>$CLMGR_TMPLOG
                    if (( $rc != RC_SUCCESS )); then
                        dspmsg -s $CLMGR_SET $CLMGR_MSGS 855 "\nERROR: the attempt to modify the Resource Optimized High Availability settings for \"%1\$s\" has failed.\n\n" $node 1>&2
                        return $rc
                    fi
                done
            else
                #
                # Cloud Connectivity failed; Inform user and exit
                #
                typeset -i cmd_rc=0
                rc=$RC_ERROR

                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 1505 "\nERROR: Cloud connectivity failed. Possible reasons are:\n\
a. PowerHA cluster or site nodes are not Cloud VMs.\n\
b. Supplied AUTHKEY and SERVICE values are not valid.\n\
You can cross check and perform the operation again.\n\n" 1>&2

                # Perform cleanup of entries which failed validation
                for node in $nodelist; do
                    print "$0()[$LINENO]($SECONDS): /usr/es/sbin/cluster/utilities/clchpowervs -r -n $node" >>$CLMGR_TMPLOG
                    /usr/es/sbin/cluster/utilities/clchpowervs -r -n $node
                    cmd_rc=$?
                    (( rc |= $cmd_rc ))
                    print "$0()[$LINENO]($SECONDS): clchpowervs RC: $cmd_rc" >>$CLMGR_TMPLOG
                    if (( $cmd_rc != RC_SUCCESS )); then
                        dspmsg -s $CLMGR_SET $CLMGR_MSGS 855 "\nERROR: the attempt to modify the Resource Optimized High Availability settings for \"%1\$s\" has failed.\n\n" $node 1>&2
                    fi
                done

                if [[ "$operation" != "add" ]]; then
                    #
                    # Change operation failed; restore the old entries to PowerHA configuration (HACMPnode ODM)
                    #
                    for node in $nodelist; do
                        print "$0()[$LINENO]($SECONDS): /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node $oldargs" >>$CLMGR_TMPLOG
                        /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node $oldargs
                        cmd_rc=$?
                        (( rc |= $cmd_rc ))
                        print "$0()[$LINENO]($SECONDS): clchpowervs RC: $cmd_rc" >>$CLMGR_TMPLOG
                        if (( $cmd_rc != RC_SUCCESS )); then
                            dspmsg -s $CLMGR_SET $CLMGR_MSGS 855 "\nERROR: the attempt to modify the Resource Optimized High Availability settings for \"%1\$s\" has failed.\n\n" $node 1>&2
                        fi
                    done
                fi

                return $rc
            fi

        else  # [[ "$operation" == @(delete|remove) ]]
            if [[ -n $apikey || -n $crn ]]
            then
                dspmsg -s $CLMGR_SET $CLMGR_MSGS 1491 "Warning: when the \"%1\$s\" input is used with a value of \"%2\$s\", all other option(s) are invalid and will be disregarded.\n" ACTION $operation
            fi

            for node in $nodelist; do
                print "$0()[$LINENO]($SECONDS): /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node" >>$CLMGR_TMPLOG
                /usr/es/sbin/cluster/utilities/clchpowervs $action -n $node
                rc=$?
                print "$0()[$LINENO]($SECONDS): clchpowervs RC: $rc" >>$CLMGR_TMPLOG
                if (( $rc != RC_SUCCESS )); then
                    dspmsg -s $CLMGR_SET $CLMGR_MSGS 855 "\nERROR: the attempt to modify the Resource Optimized High Availability settings for \"%1\$s\" has failed.\n\n" $node 1>&2
                    return $rc
                fi
            done

        fi # end of delete/remove operation

        # Note that PowerHA configuration is updated
        change_done=1

    fi

    if (( rc == RC_SUCCESS )); then
        #===========================================================
        # Set the "handle" attribute in the HACMPcluster class
        # to zero to indicate that an unsynced change exists in
        # the cluster configuration. 
        #===========================================================
        if (( change_done )); then
            print "\
HACMPcluster:
\thandle=0" | /usr/bin/odmchange -o HACMPcluster
        fi
    fi

    #===========================================================
    : If output from this operation was requested, retrieve it
    #===========================================================
    if (( $rc == RC_SUCCESS )); then
        if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then
            # Print the added entries. For this, pick any single node from list
            typeset anynode=$(echo $nodelist | cut -f1 -d" ")
            typeset args=$(clodmget -q "name=$anynode and object like POWERVS_*" -n -d"=" -f object,value HACMPnode)
            print "$0()[$LINENO]($SECONDS): Configured Cloud ROHA Entries:\nNodes:$nodelist\n\"$args\"" >>$CLMGR_TMPLOG
        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" \
        "manage cluster -h" "CLUSTER:" "$CLMGR_PROGNAME" 1>&2
    fi

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