#!/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.
#
#  Copyright (C) Altran ACT S.A.S. 2017,2018,2019,2021.  All rights reserved.
#
#  ALTRAN_PROLOG_END_TAG
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r721 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_network.sh 1.10 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 1990,2010 
# 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/lib/ksh93/hacmp/KLIB_HACMP_modify_network.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM

# 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_network

=head1 SYNOPSIS

 clmgr modify network <network> \
             [ NAME=<new_network_label> ] \
             [ TYPE={ether|XD_data|XD_ip}} ] \
             [ {NETMASK=<###.###.###.###> | PREFIX=<###>} ] \
             [ PUBLIC={true|false} ] \
             [ RESOURCE_DIST_PREF={AC|ACS|C|CS|CPL|ACPL|ACPLS|NOALI} ] \
             [ SOURCE_IP=<service_or_persistent_ip> ] \
             [ UNSTABLE_THRESHOLD=<1...99> ] \
             [ UNSTABLE_PERIOD=<1...120> ]

 NOTE: the TYPE defaults to "ether" if not specified.
 NOTE: when adding, the default is to construct an IPv4
       network using a netmask of "255.255.255.0". To
       create an IPv6 network, specify a valid prefix.
 NOTE: AC    == Anti-Collocation
       ACS   == Anti-Collocation with Source
       C     == Collocation
       CS    == Collocation with Source
       CPL   == Collocation with Persistent Label
       ACPL  == Anti-Collocation with Persistent Label
       ACPLS == Anti-Collocation with Persistent Label and Source
       NOALI == Disable Firstalias
 NOTE: "SOURCE_IP" must be a service label if "RESOURCE_DIST_PREF"
       is set to either "CS" or "ACS".
 NOTE: the aliases for "network" are "ne" and "nw".

=head1 DESCRIPTION

Attempts to modify the specified PowerHA network
to conform to the provided specifications.

=head1 ARGUMENTS

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

 2. network [REQUIRED] [string]
    The label of the network that is to be modified.

 3. new_network [OPTIONAL] [string]
    The new label to be applied to the specified network.

 4. type [OPTIONAL] [string]
    A new type for the specified network (i.e. "ether", "ib",
    etcetera...; see the HACMPnim ODM for all types).

 5. netmask [OPTIONAL] [string]
    A new IPv4 netmask to enforce within the specified network.

 6. prefix [OPTIONAL] [string]
    A new IPv6 prefix to enforce within the specified network.

 7. public [OPTIONAL] [string]
    A Boolean-like flag indicating is this network is public
    or private.

 8. rdp [OPTIONAL] [string]
    An indicator of the resource distribution preference
    for this network.

 9. source_ip [OPTIONAL] [string]
    A service or persistent IP address that is to be used as a
    source address on the selected network. An appropriate choice
    must be made depending on the distribution preference that
    has been specified. A service label must be chosen if the
    distribution preference is "Collocation with Source" or
    "Anti-Collocation with Source".

 10. unstable_theshold [OPTIONAL] [integer]
    Integer specifying the event threshold for network stability.

 11. unstable_period [OPTIONAL] [integer]
    Integer specifying the event period for network stability.


=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_network {
    . $HALIBROOT/log_entry "$0()" "$CL"
    : version=@(#)  7d4c34b 43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_network.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
    : INPUTS: $*

    typeset -n properties=$1
    typeset    network=${2//\"/}
    typeset    new_network=${3//\"/}
    typeset    type=${4//\"/}
    typeset    netmask=${5//\"/}
    typeset    prefix=${6//\"/}
    typeset -l public=${7//\"/}
    typeset    rdp=${8//\"/}
    typeset    source_ip=${9//\"/}
    typeset    unstable_threshold=${10//\"/}
    typeset    unstable_period=${11//\"/}  

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

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

    #===================================
    : Declare and initialize variables
    #===================================
    typeset nodename= oOpt=
    typeset -u uc_value=
    typeset -u typeUC=$type
    typeset -i rc=$RC_UNKNOWN
    typeset -A nwattrs
    typeset -i i=0

    if [[ -n $rdp ]]; then
        uc_value=$rdp
        case $uc_value in
            AC)    rdp=rdp_anti_collocation ;;
            ACS)   rdp=sldp_anti_collocation_and_first ;;
            C)     rdp=rdp_collocation ;;
            CS)    rdp=sldp_collocation_and_first ;;
            CPL)   rdp=sldp_collocation_with_persistent ;;
            ACPL)  rdp=sldp_anti_collocation_with_persistent ;;
            ACPLS) rdp=sldp_anti_collocation_with_persistent_and_first ;;
            NOALI) rdp=sldp_firstalias_none ;;
            *)    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 '\nERROR: invalid value specified for "%1$s":  "%2$s"\n\n' RESOURCE_DIST_PREF "$rdp" 1>&2
                  typeset vals="
        AC   (Anti-Collocation)
        C    (Collocation)
        CPL  (Collocation with Persistent Label)
        ACPL (Anti-Collocation with Persistent Label)"
                  /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "$vals" 1>&2
                 rc=$RC_INCORRECT_INPUT
            ;;
        esac
    fi

    #================================================================
    : Assuming an object was specified, see if it is a known object
    #================================================================
    if [[ $network != *([[:space:]]) ]]; then
        CL=$LINENO KLIB_HACMP_is_known_network "$network"
        (( $? != RC_SUCCESS )) && rc=$RC_NOT_FOUND
    fi

    #=================
    : Validate input
    #=================
    if [[ -z $network ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 100 "\nERROR: a name/label must be provided.\n\n" 1>&2
        rc=$RC_MISSING_INPUT

    elif (( $rc == RC_NOT_FOUND )); then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$network" 1>&2
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 150 "Available Networks:\n\n" 1>&2

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

    if [[ -n $new_network && -n "${new_network//[a-zA-Z0-9_]/}" ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 105 "\nERROR: one or more invalid characters were detected in \"%1\$s\" (\"%2\$s\").\n\nValid characters include letters, numbers, and underscores only.\n\n" "$new_network" "${new_network//[a-zA-Z0-9_]/}" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ -n $typeUC && $typeUC != @(E|XD_D|XD_I)* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" TYPE "$type" 1>&2
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "ether, XD_data, XD_ip" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    typeset Eopt="" Lopt=""
    if [[ $unstable_threshold != *([[:space:]]) ]]; then
        CL=$LINENO verify_numeric_range "$unstable_threshold" 1 99 UNSTABLE_THRESHOLD
        (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT || Eopt="-e $unstable_threshold"
    fi
    if [[ $unstable_period != *([[:space:]]) ]]; then
        CL=$LINENO verify_numeric_range "$unstable_period" 1 120 UNSTABLE_PERIOD
        (( $? != RC_SUCCESS )) && rc=$RC_INCORRECT_INPUT || Lopt="-l $unstable_period"
    fi

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

        #==================================================
        : If some of the required attributes are missing,
        : then just use the existing values.
        #==================================================
        CL=$LINENO KLIB_HACMP_get_network_attributes "$network" nwattrs
        if [[ -z $type ]]; then
            for key in ${!nwattrs[*]}; do
                if [[ $key == TYPE*([[:digit:]]) ]]; then
                    type=${nwattrs[$key]}
                    break
                fi
            done
        else
            case $typeUC in
                   E*) type="ether"   ;;
                XD_D*) type="XD_data" ;;
                XD_I*) type="XD_ip"   ;;
            esac
        fi
        if [[ -z $netmask ]]; then
            for key in ${!nwattrs[*]}; do
                if [[ $key == NETMASK*([[:digit:]]) ]]; then
                    netmask=${nwattrs[$key]}
                    break
                fi
            done
        fi
        if [[ -z $public ]]; then
            for key in ${!nwattrs[*]}; do
                if [[ $key == PUBLIC*([[:digit:]]) ]]; then
                    public=${nwattrs[$key]}
                    break
                fi
            done
        else
            CL=$LINENO verify_in_set PUBLIC "$public" "false, private, true, public" public
            if (( $? != RC_SUCCESS )); then
                rc=$RC_INCORRECT_INPUT
            else
                case $public in
                    true)  public="public"  ;;
                    false) public="private" ;;
                esac
            fi
        fi

        if [[ -z $type && -z $rdp ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" TYPE 1>&2
            rc=$RC_MISSING_INPUT
        fi
        if [[ -z $netmask && -z $prefix && -z $rdp ]];then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 408 "\nERROR: either \"%1\$s\" or \"%2\$s\" must be specified.\n\n" "NETMASK (IPv4)" "PREFIX (IPv6)" 1>&2
            rc=$RC_MISSING_INPUT
        fi
        if [[ -n $netmask && -n $prefix ]];then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 "\nERROR: conflicting options were provided,\n\       \"%1\$s\" versus \"%2\$s\".\n\n" NETMASK PREFIX 1>&2
            rc=$RC_INCORRECT_INPUT
        fi
        if [[ -z $public && -z $rdp ]]; then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" PUBLIC 1>&2
            rc=$RC_MISSING_INPUT
        fi
        if [[ -n $rdp ]]; then
            #====================================================
            : Check that the specified network has a service IP
            #====================================================
            typeset -i valid=0
            typeset SIs
            typeset -A attrs
            CL=$LINENO KLIB_HACMP_list_service_ip SIs
            if (( ${#SIs[*]} > 0 )); then
                for (( i=0; i<${#SIs[*]}; i++ )); do
                    if [[ ${SIs[$i]} != *([[:space:]]) ]]; then
                        CL=$LINENO KLIB_HACMP_get_service_ip_attributes "${SIs[$i]}" attrs
                        for key in ${!attrs[*]}; do
                            if [[ $key == NETWORK*([[:digit:]]) ]]; then
                                [[ ${attrs[$key]} == $network ]] && valid=1
                                break
                            fi
                        done
                    fi
                done
            fi
            if (( ! valid )); then
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 409 "\nERROR: the resource distribution preference requires at least one\n       service IP to be defined in the cluster, on the specified\n       network (\"%1\$s\").\n\n" "$network" 1>&2
                rc=$RC_MISSING_DEPENDENCY
            fi
        fi

        if (( $rc == RC_UNKNOWN )); then
            if [[ -n $new_network || -n $type || -n $netmask || -n $public ]]
            then
                if [[ -n $new_network ]]; then
                    oOpt=" -o $new_network "
                fi

                print "$0()[$LINENO]($SECONDS): clmodnetwork -m -n \"$network\" $oOpt -i \"$type\" -s \"$netmask\" -t \"$public\" $Eopt $Lopt" >>$CLMGR_TMPLOG  # Always log commands
                clmodnetwork -m \
                                      -n "$network" \
                                      $oOpt \
                                      -i "$type" \
                                      -s "$netmask" \
                                      -t "$public" \
                                      $Eopt \
                                      $Lopt
                rc=$?
                print "clmodnetwork RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
                (( $rc != RC_SUCCESS )) && rc=$RC_ERROR
            fi
        fi

        #====================================================
        : Handle resource distribution policy modifications
        #====================================================
        if (( $rc == RC_SUCCESS )) && [[ -n $rdp ]]; then
            typeset fOpt=""
            [[ -n $new_network ]] && network=$new_network
            [[ -n $source_ip   ]] && fOpt=" -f $source_ip"

            print "$0()[$LINENO]($SECONDS): $HAUTILS/clmodnetwork -m -n \"$network\" -p \"$rdp\"$fOpt" >>$CLMGR_TMPLOG  # Always log commands
            $HAUTILS/clmodnetwork -m -n "$network" -p "$rdp"$fOpt
            rc=$?
            print "clmodnetwork RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
            if (( $rc != RC_SUCCESS )); then
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 217 "\nERROR: failed to set the resource distribution preference for network \"%1\$s\" to \"%2\$s\".\n\n" "$name" "$rdp" 1>&2
            fi
        fi
    fi

    #===========================================================
    : If output from this operation was requested, retrieve it
    #===========================================================
    if (( $rc == RC_SUCCESS )); then
        [[ -n $new_network ]] && network=$new_network
        if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then
            CL=$LINENO KLIB_HACMP_get_network_attributes "$network" properties
        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
        print -u2 ""
        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 network -h" "NETWORK:" "$CLMGR_PROGNAME" 1>&2
    fi

    log_return_msg "$rc" "$0()" "$LINENO"
    return $?
} # End of "KLIB_HACMP_modify_network()"
#================================================
# The following, commented line enforces coding
# standards when this file is edited via vim.
#================================================
# vim:tabstop=4:shiftwidth=4:expandtab:smarttab
#================================================

