#!/bin/ksh93
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r721 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_cod.sh 1.3.1.10 
#  
# Licensed Materials - Property of IBM 
#  
# Restricted Materials of IBM 
#  
# COPYRIGHT International Business Machines Corp. 2012,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 

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

=head1 VERSION

 Version Number:  1.3.1.10
 Last Extracted:  10/1/16 00:22:31
 Last Changed:    9/29/16 14:17:51

 Path, Component, Release(, Level):
 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_cod.sh, hacmp.assist, 61haes_r721, 1639C_hacmp721

=head1 SYNOPSIS

clmgr add cod <APPCTRL> \
 [ USE_DESIRED="Yes|No"> ] \
 [ OPTIMAL_MEM=#.## ]  \
 [ OPTIMAL_CPU=# ]  \
 [ OPTIMAL_PU=#.## ] \
 [ OPTIMAL_VP=# ]

 NOTE: the aliases for "cod" are "cuod", "dlpar" and "roha".

=head1 DESCRIPTION

  Attempts to configure Resource Optimized High Availability parameters within the specified
   application controller.
  Resource Optimized High Availability parameters enable the resources provisioning for
   Dynamic LPAR, and CoD operations.
  Resource Optimized High Availability parameters describe the optimal level of resources
   for a given application controller:
   - optimal amount of memory expressed in GB,
   - optimal number of real processors (in dedicated processing mode),
   - optimal number of processing units (in shared processing mode),
   - optimal number of virtual processors (in shared processing mode).

  As an alternative, you can specify 'Use desired level from the LPAR profile' to indicate
   that the application controller just needs the LPAR to reach its desired
   level of resources as indicated into the profile.

=head1 ARGUMENTS

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

  2. application_controller [REQUIRED] [string]
  This is the application controller for which you will configure
   Resource Optimized High Availability, i.e mechanisms based on
   Dynamic LPAR, and CoD resources provisioning.

  3. USE_DESIRED [OPTIONAL] [string]
  Enter 'Yes' if you only want that the LPAR hosting
   your node reaches the level of resources indicated by the
   'Desired level of resources' of the LPAR profile.
   Enter 'Yes', if you trust the desired level of LPAR
   profile to fit the needs of your application controller.
  Enter 'No' if you prefer enter exact optimal values
   for memory, for number of processors (in dedicated
   processing mode), for number of processing units and
   number of virtual processors (in shared
   processing mode), which match the needs of your application
   controller, and to better control the level of resources
   to be allocated to your application controller.

  4. OPTIMAL_MEM [OPTIONAL] [int]
  Enter the amount of memory PowerHA SystemMirror will
   attempt to acquire for the node before starting this
   application controller.
  This OPTIMAL_MEM value can only be set if the
   USE_DESIRED value is set to 'No'.
  Enter the value in multiple of 1/4, 1/2, 3/4, or 1 GB.
   For examples:
    1    would represent 1 GB or 1024 MB,
    1.25 would represent 1.25 GB or 1280 MB,
    1.50 would represent 1.50 GB or 1536 MB,
    1.75 would represent 1.75 GB or 1792 MB.
  If this amount of memory is not satisfied, PowerHA
   SystemMirror will take resource group recovery actions to
   move the resource group with this application controller
   to another node.

  5. OPTIMAL_CPU [OPTIONAL] [int]
  Enter the amount of CPUs PowerHA SystemMirror will
   attempt to allocate for the node before starting this
   application controller.
  This OPTIMAL_CPU value can only be set if the
   USE_DESIRED value is set to 'No'.
  This value is only used on nodes which support allocation of
   CPUs, i.e. LPAR running in dedicated processing mode.
  If this amount of CPUs is not satisfied, PowerHA
   SystemMirror will take resource group recovery
   actions to move the resource group with this
   application controller to another node.

  6. OPTIMAL_PU [OPTIONAL] [float]
  Enter the amount of processing units PowerHA SystemMirror will
   attempt to allocate for the node before starting this application
   controller.
  This OPTIMAL_PU value can only be set if the USE_DESIRED
   value is set to 'No'.
  Processing units are specified as a decimal number with two decimal
   places, ranging from 0.10 to 255.90.
  This value is only used on nodes which support allocation of processing
   units, i.e. LPAR running in shared processing mode.
  If this amount of PUs is not satisfied, PowerHA SystemMirror will
   take resource group recovery actions to move the resource group with this
   application controller to another node.

  6. OPTIMAL_VP [OPTIONAL] [int]
  Enter the amount of virtual CPUs PowerHA SystemMirror will
   attempt to allocate for the node before starting this
   application controller.
  This OPTIMAL_VP value can only be set if the
   USE_DESIRED value is set to 'No'.
  This value is only used on nodes which support allocation of processing
   units, i.e. LPAR running in shared processing mode.
  If this amount of virtual CPUs is not satisfied, PowerHA
   SystemMirror will take resource group recovery
   actions to move the resource group with this
   application controller to another node.

=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

=head1 COPYRIGHT

  COPYRIGHT International Business Machines Corp. 2005,2015
  All Rights Reserved

=cut
} # End of POD-formatted documentation.


function KLIB_HACMP_add_cod {
    LINENO=2 . $HALIBROOT/log_entry "$0()" "$CL"
    : version=1.3.1.10, src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_cod.sh, hacmp.assist, 61haes_r721, 1639C_hacmp721
    : INPUTS: $*

    typeset -n properties=$1
    typeset application_controller=${2//\"/}
    typeset use_desired=${3//\"/}
    typeset optimal_mem=${4//\"/}
    typeset optimal_cpu=${5//\"/}
    typeset optimal_pu=${6//\"/}
    typeset optimal_vp=${7//\"/}

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

    #===================================
    : Declare and initialize variables
    #===================================
    typeset -i rc=$RC_UNKNOWN
    typeset -i RC_INVALID_MEM_VALUE=2
    typeset -i RC_INVALID_PROC_UNITS_VALUE=3
    typeset -i RC_INVALID_PROC_AND_PROC_UNITS_RELATED_VALUES=4
    typeset -i RC_INVALID_PROC_UNITS_VALUE=5

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


    #=================
    : Validate input
    #=================
    elif  [[ -z $application_controller ]]; 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
    else
        CL=$LINENO KLIB_HACMP_is_known_appserver "$application_controller"
        if (( $? != RC_SUCCESS )); then
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$application_controller" 1>&2
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 140 "Available Application Controllers:\n\n" 1>&2

            typeset available
            CL=$LINENO KLIB_HACMP_list_appservers 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
            CL=$LINENO KLIB_HACMP_is_known_cod "$application_controller"
            if (( $? == RC_SUCCESS )); then
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 851 "\nERROR: \"%1\$s\" is already configured for Resource Optimized High Availability services.\n\n" "$application_controller" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi
        fi
    fi


    if (( $rc == RC_UNKNOWN )); then
        #==========================
        : Validate the string value
        #==========================
        if [[ $use_desired == *([[:space:]]) ]]; then
            # this is possible to have no value here
            use_desired=false
        else
            #=======================
            : Validate boolean value
            #=======================
            for PAIR in "USE_DESIRED|$use_desired"; do
                # Check it is either yes/true or no/false
                typeset ATTR=${PAIR%%\|*}
                typeset -l VALUE_LC=${PAIR##*\|}
                [[ $VALUE_LC == *([[:space:]]) ]] && continue

                if [[ $VALUE_LC != @(0|1|y|t|n|f)* ]]; then
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\".\n" "$ATTR" "$VALUE_LC" 1>&2
                    /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "Yes, No" 1>&2
                    rc=$RC_INCORRECT_INPUT
                else
                    if [[ $VALUE_LC == @(1|y|t)* ]]; then
                        use_desired=true
                    fi
                    if [[ $VALUE_LC == @(0|n|f)* ]]; then
                        use_desired=false
                    fi
                fi
            done
            typeset -ri use_desired_set=1
        fi


        #==============================
        : Validate all integer values
        #==============================
        for PAIR in "OPTIMAL_CPU|$optimal_cpu" \
            "OPTIMAL_VP|$optimal_vp"; do
          typeset ATTR=${PAIR%%\|*}
          typeset VALUE=${PAIR##*\|}
              if [[ -n $VALUE ]]; then
                  if [[ $VALUE != +([[:digit:]]) ]]; then
                      /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 111 "\nERROR: \"%1\$s\" requires a positive, integer value.\n\n" "$ATTR" 1>&2
                      rc=$RC_INCORRECT_INPUT
                  else
                      # now we are sure it is an integer
                      typeset -l attrname=$ATTR
                      eval "typeset -i $attrname=$VALUE"
                  fi
              fi
        done


        #==============================
        : Validate all float values
        #==============================
        for PAIR in "OPTIMAL_PU|$optimal_pu" \
            "OPTIMAL_MEM|$optimal_mem"; do
          typeset ATTR=${PAIR%%\|*}
          typeset VALUE=${PAIR##*\|}
              if [[ -n $VALUE ]]; then
                  if [[ $VALUE != +([[:digit:]]) &&
                              $VALUE != +([[:digit:]])\.+([[:digit:]]) ]] then
                      /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 111 "\nERROR: \"%1\$s\" requires a positive, decimal numeric value.\n\n" "$ATTR" 1>&2
                      rc=$RC_INCORRECT_INPUT
                  else
                      # now we are sure it is a float
                      typeset -l attrname=$ATTR
                      eval "typeset -F2 $attrname=$VALUE"
                  fi
              fi
        done

        #=====================================
        : Verify consistency between parameter
        #=====================================
        if [[ $use_desired == false ]]; then
            if [[ -z "$optimal_mem$optimal_cpu$optimal_pu$optimal_vp" ]]; then
                CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 801  "\nERROR: either use desired level from the LPAR profile (USE_DESIRED set to \"Yes\") or one optimal setting at least must be set.\n\n" 1>&2
                rc=$RC_MISSING_INPUT
            fi
        else
            #
            : use_desired is set to 1, in that case we can accept
            :  - either null values
            :  - or if values are set, then only 0 as values
            #
            typeset -i error=0
            [[ -n $optimal_mem && $optimal_mem != 0.00 ]] && error=1
            [[ -n $optimal_cpu && $optimal_cpu != 0 ]] && error=1
            [[ -n $optimal_pu  && $optimal_pu  != 0.00 ]] && error=1
            [[ -n $optimal_vp  && $optimal_vp  != 0 ]] && error=1
            if (( $error == 1)); then
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 800 "\nERROR: to set an optimal value, you cannot use desired level from the LPAR profile (USE_DESIRED must be set to \"No\").\n" 1>&2
                rc=$RC_INCORRECT_INPUT
            fi
        fi
    fi


    #=============================================================
    : Set the Resource Optimized High Availability settings if no input errors have been detected
    #=============================================================
    if (( $rc == RC_UNKNOWN )); then
        typeset mOpt= cOpt= pOpt= vOpt=
        [[ $use_desired == true ]] && uOpt=" -u 1 " || uOpt=" -u 0"
        [[ -n $optimal_mem && $optimal_mem != 0.00 ]] && mOpt=" -m $optimal_mem" || mOpt=" "
        [[ -n $optimal_cpu && $optimal_cpu != 0 ]]    && cOpt=" -c $optimal_cpu" || cOpt=" "
        [[ -n $optimal_pu  && $optimal_pu != 0.00 ]]  && pOpt=" -p $optimal_pu"  || pOpt=" "
        [[ -n $optimal_vp  && $optimal_vp != 0 ]]     && vOpt=" -v $optimal_vp"  || vOpt=" "

        print -- "$0()[$LINENO]($SECONDS): clchserv -o \"$application_controller\"$uOpt$mOpt$cOpt$pOpt$vOpt" >>$CLMGR_TMPLOG
        clchserv -o "$application_controller"$uOpt$mOpt$cOpt$pOpt$vOpt
        rc=$?
        print -- "$0()[$LINENO]($SECONDS): clchserv rc=$rc" >>$CLMGR_TMPLOG

        if (( $rc == RC_INVALID_MEM_VALUE )); then
            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 802 "\nERROR: the optimal amount of memory (OPTIMAL_MEM) must be a multiple of 0.25.\n\n" 1>&2
            rc=$RC_INCORRECT_INPUT

        elif (( $rc == RC_INVALID_PROC_UNITS_VALUE )); then
            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 803 "\nERROR: the optimal number of processing units (OPTIMAL_PU) must be a multiple of 0.01.\n\n"  1>&2
            rc=$RC_INCORRECT_INPUT

        elif (( $rc == RC_INVALID_PROC_UNITS_VALUE )); then
            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 805 "\nERROR: the optimal number of processing units (OPTIMAL_PU) must be at least 0.1, a tenth of a processor for reasonableness, if a value other than zero specified.\n\n"  1>&2
            rc=$RC_INCORRECT_INPUT

        elif (( $rc != RC_SUCCESS )); then
            CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 855 "\nERROR: the attempt to define Resource Optimized High Availability settings for \"%1\$s\" has failed.\n\n" "$application_controller" 1>&2
            rc=$RC_ERROR

            #===========================================================
            : If output from this operation was requested, retrieve it
            #===========================================================
        elif (( $rc == RC_SUCCESS )); then
            if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then
                CL=$LINENO KLIB_HACMP_get_cod_attributes "$application_controller" properties
            fi
        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" \
            "add cod -h" "COD:" "$CLMGR_PROGNAME" 1>&2
    fi


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