#!/bin/ksh93
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# 61haes_r714 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_dependency.sh 1.4 
#  
# 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 
# @(#)09	1.4  src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_dependency.sh, hacmp.assist, 61haes_r714 8/6/13 16:54:48

#================================================
# 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_add_dependency

=head1 VERSION

 Version Number:  1.4
 Last Extracted:  1/31/14 04:41:52
 Last Changed:    8/6/13 16:54:48

 Path, Component, Release(, Level):
 src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_dependency.sh, hacmp.assist, 61haes_r714

=head1 SYNOPSIS

 Temporal Dependency (parent ==> child)
 clmgr add dependency \
             PARENT=<rg#1> \
             CHILD="<rg#2>[,<rg#2>,<rg#n>...]"

 Temporal Dependency (start/stop after)
 clmgr add dependency \
             {STOP|START}=<rg#2> \
             AFTER=<rg#1>

 Location Dependency (colocation)
 clmgr add dependency \
             SAME={NODE|SITE} \
             GROUPS="<rg1>,<rg2>[,<rg#n>...]"

 Location Dependency (anti-colocation)
 clmgr add dependency \
             TYPE=DIFFERENT_NODES \
             HIGH="<rg1>,<rg2>,..." \
             INTERMEDIATE="<rg3>,<rg4>,..." \
             LOW="<rg5>,<rg6>,..."

 Acquisition/Release Order
 clmgr add dependency \
             TYPE={ACQUIRE|RELEASE} \
             { SERIAL="{<rg1>,<rg2>,...|ALL}" |
               PARALLEL="{<rg1>,<rg2>,...|ALL}" }

 NOTE: the alias for "dependency" is "de".

=head1 DESCRIPTION

 Creates a new resource group dependency within the cluster:

    Temporal Dependency: (i.e. startup order matters)
        Parent/Child, Parent/Children
        Start/Stop After, Aquire/Release

    Location Dependency: (i.e. node location matters most)
        CoLocation: same node, same site
        Anti-CoLocation: different node (startup order can also be specified)

=head1 ARGUMENTS

 1. parent [OPTIONAL] {string]
    The label of a resource group that will be a parent.

 2. children [OPTIONAL] {string]
    The labels of one or more resource groups that will be
    children of the specified parent resource group.

 3. same [OPTIONAL] {string]
    An indicator of whether or not to create a "same node"
    or a "same site" colocation dependency.

 4. groups [OPTIONAL] {string]
    The labels of one or more resource groups to include
    in the colocation dependency

 5. high [OPTIONAL] {string]
    The labels of one or more resource groups to include
    in an anti-colocation dependency, and give the highest
    startup priority.

 6. intermediate [OPTIONAL] {string]
    The labels of one or more resource groups to include
    in an anti-colocation dependency, and give intermediate
    startup priority.

 7. low [OPTIONAL] {string]
    The labels of one or more resource groups to include
    in an anti-colocation dependency, and give the lowest
    startup priority.

 8. stop [OPTIONAL] {string]
    The label of a resource group that will be stopped
    after the specified "AFTER" resource group.

 9. start [OPTIONAL] {string]
    The label of a resource group that will be started
    after the specified "AFTER" resource group.

 10. after [OPTIONAL] {string]
    The label of a resource group that will be stopped or
    started *before* the list of other resource groups
    provided via "STOP" or "START".

 11. type [OPTIONAL] {string}
    The type of dependency to create. This is totally optional
    for all true dependency types, which can be easily inferred
    from the provided arguments. However, type is required for
    setting the resource group processing order.

 12. serial [OPTIONAL] {string}
    The labels of one or more resource groups that are to
    be aquired/release serially, in the order specified.
    Any groups not specified here will continue to be
    acquired/released in parallel (the default behavior).

 13. parallel [OPTIONAL] {string}
    The labels of one or more resource groups that are to
    be aquired/release in parallel (i.e. at the same time).
    Any groups not specified here will be acquired/released
    serially, in the order previously specified.

=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,2010
All Rights Reserved

=cut
} # End of POD-formatted documentation.


function KLIB_HACMP_add_dependency {
    LINENO=2 . $HALIBROOT/log_entry "$0()" "$CL"
    : version=1.4, src/43haes/lib/ksh93/hacmp/KLIB_HACMP_add_dependency.sh, hacmp.assist, 61haes_r714
    : INPUTS: $*

    typeset parent=${1//\"/}
    typeset children=${2//\"/}
    typeset -u same=${3//\"/}
    typeset groups=${4//\"/}
    typeset high=${5//\"/}
            high=${high//,/ }
    typeset intermediate=${6//\"/}
            intermediate=${intermediate//,/ }
    typeset low=${7//\"/}
            low=${low//,/ }
    typeset -i i=0
    for (( i=0; i<7; i++ )); do
        (( $# == 0 )) && break
        shift
    done

    typeset stop=${1//\"/}
    typeset start=${2//\"/}
    typeset after=${3//\"/}
    typeset type=${4//\"/}
    typeset serial=${5//\"/}
    typeset parallel=${6//\"/}

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

    #===================================
    : Declare and initialize variables
    #===================================
    typeset -i rc=$RC_UNKNOWN
    typeset -u TYPE=$type
    if [[ -n $serial ]]; then
        serial=${serial//,/ }
        serial=${serial//+([[:space:]])/ }
        serial=${serial#+([[:space:]])}
        serial=${serial%+([[:space:]])}
    fi
    if [[ -n $parallel ]]; then
        parallel=${parallel//,/ }
        parallel=${parallel//+([[:space:]])/ }
        parallel=${parallel#+([[:space:]])}
        parallel=${parallel%+([[:space:]])}
    fi
    if [[ -n $parent ]]; then
        parent=${parent//,/ }
        parent=${parent//+([[:space:]])/ }
        parent=${parent#+([[:space:]])}
        parent=${parent%+([[:space:]])}
    fi
    if [[ -n $children ]]; then
        children=${children//,/ }
        children=${children//+([[:space:]])/ }
        children=${children#+([[:space:]])}
        children=${children%+([[:space:]])}
    fi
    if [[ -n $groups ]]; then
        groups=${groups//,/ }
        groups=${groups//+([[:space:]])/ }
        groups=${groups#+([[:space:]])}
        groups=${groups%+([[:space:]])}
    fi
    if [[ -n $high ]]; then
        high=${high//,/ }
        high=${high//+([[:space:]])/ }
        high=${high#+([[:space:]])}
        high=${high%+([[:space:]])}
    fi
    if [[ -n $intermediate ]]; then
        intermediate=${intermediate//,/ }
        intermediate=${intermediate//+([[:space:]])/ }
        intermediate=${intermediate#+([[:space:]])}
        intermediate=${intermediate%+([[:space:]])}
    fi
    if [[ -n $low ]]; then
        low=${low//,/ }
        low=${low//+([[:space:]])/ }
        low=${low#+([[:space:]])}
        low=${low%+([[:space:]])}
    fi
    if [[ -n $stop ]]; then
        stop=${stop//,/ }
        stop=${stop//+([[:space:]])/ }
        stop=${stop#+([[:space:]])}
        stop=${stop%+([[:space:]])}
    fi
    if [[ -n $start ]]; then
        start=${start//,/ }
        start=${start//+([[:space:]])/ }
        start=${start#+([[:space:]])}
        start=${start%+([[:space:]])}
    fi
    if [[ -n $after ]]; then
        after=${after//,/ }
        after=${after//+([[:space:]])/ }
        after=${after#+([[:space:]])}
        after=${after%+([[:space:]])}
    fi

    if [[ -n $parent || -n $children ]]; then
        TYPE="PARENT_CHILD"
    elif [[ -n $same || -n $groups ]]; then
       case $same in
           *NODE*) TYPE="NODECOLLOCATION" ;;
           *SITE*) TYPE="SITECOLLOCATION" ;;
       esac
    elif [[ -n $high || -n $intermediate || -n $low ]]; then
        TYPE="ANTICOLLOCATION"
    elif [[ -n $after ]]; then
        TYPE="AFTER"
        if [[ -n $stop ]]; then
            TYPE="STOP_AFTER"
        elif [[ -n $start ]]; then
            TYPE="START_AFTER"
        fi
    fi

    #================================================================
    : 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 $TYPE && -n "$serial$parallel" ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 37 "\nERROR: option \"%1\$s\" is required when any of the following option(s)\n       are used: %2\$s\n\n" TYPE "SERIAL, PARALLEL" 1>&2
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "ACQUIRE, RELEASE" 1>&2
        rc=$RC_MISSING_INPUT
    fi
    
    if [[ -n $serial && -n $parallel ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 "\nERROR: conflicting options were provided, \"%1\$s\" versus \"%2\$s\".\n\n" "SERIAL" "PARALLEL" 1>&2
        rc=$RC_MISSING_INPUT
    fi
    
    if [[ -n $TYPE && -n "$serial$parallel" && $TYPE != @(A|R)* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\": \"%2\$s\"\n\n" TYPE "$TYPE" 1>&2
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "ACQUIRE, RELEASE" 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if [[ $TYPE == "PARENT_CHILD" && -z $parent ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" PARENT 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if [[ $TYPE == "PARENT_CHILD" && -z $children ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" CHILD 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if [[ -n $parent && $parent == *[[:space:]]* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 210 "\nERROR: only one resource group may be specified as the parent in a\n       \"parent/child\" dependency:  PARENT=\"%1\$s\"\n\n" "$parent" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ $TYPE == *AFTER ]] && [[ -z $stop && -z $start ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" STOP/START 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if [[ -n $after && $after == *[[:space:]]* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 210 "\nERROR: only one resource group may be specified as the primary resource group\n       in a \"STOP_AFTER\" dependency:  AFTER=\"%1\$s\"\n\n" "$after" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ -n $same && $same != *@(NODE|SITE)* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\":  \"%2\$s\"\n\n" SAME "$same" 1>&2
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "NODE, SITE" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ -n $same || -n $groups ]] && \
         [[ -n $TYPE && $TYPE != @(NODE|SITE)COLLOCATION ]]
    then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 211 "\nERROR: a dependency of type \"%1\$s\" has already been specified.\n       It will not be possible to also define a \"same node/site\" dependency\n       in the same operation.\n\n" "$TYPE" 1>&2
        rc=$RC_ERROR
    fi

    if [[ -n $same && -z $groups ]] || [[ -z $same && -n $groups ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 212 "\nERROR: to establish a \"same site/node\" dependency, the type of the\n       dependency must be specified via the SAME attribute, and two\n       or more resource groups must be specified via the GROUPS attribute.\n\n" 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if [[ -n $groups && $groups != *[[:space:]]* ]]; then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 101 "\nERROR: this operation requires the \"%1\$s\" attribute.\n\n" GROUPS 1>&2
        rc=$RC_MISSING_INPUT
    fi

    if [[ -n $high || -n $intermediate || -n $low ]] && \
         [[ $TYPE != "ANTICOLLOCATION" ]]
    then
        /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 213 "\nERROR: a dependency of type \"%1\$s\" has already been specified.\n       It will not be possible to also define a \"different nodes\" dependency\n       in the same operation.\n\n" "$TYPE" 1>&2
        rc=$RC_INCORRECT_INPUT
    fi

    if [[ "$parent $child $high $intermediate $low $groups $start $stop $after" != *([[:space:]])  ]]
    then
        typeset allRGs="$parent $child $high $intermediate $low $groups $start $stop $after"
        typeset -i all_rgs_found=1
        for rg in ${allRGs//,/ }; do
            CL=$LINENO KLIB_HACMP_is_known_rg "$rg"
            if (( $? != RC_SUCCESS )); then
                rc=$RC_INCORRECT_INPUT
                all_rgs_found=0
                /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$rg" 1>&2
            fi
        done

        if (( ! all_rgs_found )); then 
            /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 154 "Available Resource Groups:\n\n" 1>&2

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

    #==============================================================
    : Create the dependency if no input errors have been detected
    #==============================================================
    if (( $rc == RC_UNKNOWN )); then
        case $TYPE in
            AC*)
                typeset depList
                CL=$LINENO KLIB_HACMP_list_dependencies depList
                for (( i=0; i<${#depList[*]}; i++ )); do
                    [[ ${depList[$i]} != *RELEASE_SERIALLY* ]] && continue
                    break
                done
                typeset release=${depList[$i]}
                release=${release%%+([[:space:]])*}
                release=${release//,/ }

                if [[ -n $parallel ]]; then
                    serial=
                    typeset rgList
                    CL=$LINENO KLIB_HACMP_list_resourcegroups rgList
                    for (( i=0; i<${#rgList[*]}; i++ )); do
                        if [[ " ${parallel//,/ } " != *\ ${rgList[$i]}\ * ]]
                        then
                            [[ -n $serial ]] && serial="$serial "
                            serial="$serial${rgList[$i]}"
                        fi
                    done
                fi

                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgorder -c -a \"${serial//,/ }\" -r \"$release\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgorder -c -a "${serial//,/ }" -r "$release"
                rc=$?
                print "clrgorder RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
            ;;
            R*)
                typeset depList
                CL=$LINENO KLIB_HACMP_list_dependencies depList
                for (( i=0; i<${#depList[*]}; i++ )); do
                    [[ ${depList[$i]} != *ACQUIRE_SERIALLY* ]] && continue
                    break
                done
                typeset acquire=${depList[$i]}
                acquire=${acquire%%+([[:space:]])*}
                acquire=${acquire//,/ }

                if [[ -n $parallel ]]; then
                    serial=
                    typeset rgList
                    CL=$LINENO KLIB_HACMP_list_resourcegroups rgList
                    for (( i=0; i<${#rgList[*]}; i++ )); do
                        if [[ " ${parallel//,/ } " != *\ ${rgList[$i]}\ * ]]
                        then
                            [[ -n $serial ]] && serial="$serial "
                            serial="$serial${rgList[$i]}"
                        fi
                    done
                fi

                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgorder -c -a \"$acquire\" -r \"${serial//,/ }\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgorder -c -a "$acquire" -r "${serial//,/ }"
                rc=$?
                print "clrgorder RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
            ;;
            "PARENT_CHILD")
                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgdependency -t \"$TYPE\" -a -p \"$parent\" -c \"$children\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgdependency -t "$TYPE" -a -p "$parent" -c "$children"
                rc=$?
                print "clrgdependency RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
                (( $rc != RC_SUCCESS )) && rc=$RC_ERROR
            ;;
            "STOP_AFTER")
                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgdependency -t \"$TYPE\" -a -p \"$stop\" -c \"$after\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgdependency -t "$TYPE" -a -p "$stop" -c "$after"
                rc=$?
                print "clrgdependency RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
                (( $rc != RC_SUCCESS )) && rc=$RC_ERROR
            ;;
            "START_AFTER")
                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgdependency -t \"$TYPE\" -a -c \"$start\" -p \"$after\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgdependency -t "$TYPE" -a -c "$start" -p "$after"
                rc=$?
                print "clrgdependency RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
                (( $rc != RC_SUCCESS )) && rc=$RC_ERROR
            ;;
            @(NODE|SITE)COLLOCATION)
                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgdependency -t \"$TYPE\" -a -l \"$groups\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgdependency -t "$TYPE" -a -l "$groups"
                rc=$?
                print "clrgdependency RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
                (( $rc != RC_SUCCESS )) && rc=$RC_ERROR
            ;;
            "ANTICOLLOCATION")
                # IMPORTANT NOTE: the clrgdependency options "-hp", "-ip" and
                #                  "-lc" require *no* space between them and
                #                 their argument values! So don't "correct"
                #                 that, below!
                print -- "$0()[$LINENO]($SECONDS): $HAUTILS/clrgdependency -t \"$TYPE\" -u -hp\"$high\" -ip\"$intermediate\" -lp\"$low\"" >>$CLMGR_TMPLOG  # Always log commands
                $HAUTILS/clrgdependency -t "$TYPE" -u -hp"$high" -ip"$intermediate" -lp"$low"
                rc=$?
                print "clrgdependency RC: $rc" >>$CLMGR_TMPLOG  # Always log command result
                (( $rc != RC_SUCCESS )) && rc=$RC_ERROR
            ;;
            *) /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 33 "\nERROR: invalid dependency attributes were specified.\n\n" 1>&2
                rc=$RC_MISSING_INPUT
            ;;
        esac
        (( $rc == RC_ERROR )) && /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 109 "\nERROR: the operation appears to have failed.\n\n" 1>&2
    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 dependency -h" "DEPENDENCY:" "$CLMGR_PROGNAME" 1>&2
    fi

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