#!/bin/ksh93 # ALTRAN_PROLOG_BEGIN_TAG # This is an automatically generated prolog. # # Copyright (C) Altran ACT S.A.S. 2017,2018,2019,2020,2021. All rights reserved. # # ALTRAN_PROLOG_END_TAG # # @(#) df5e164 43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_resourcegroup.sh, 726, 2147A_aha726, Apr 20 2021 10:49 PM #============================================================================ # # Name: KLIB_HACMP_modify_resourcegroup # # Description: This is the main, FPATH function that is invoked by clmgr # to modify resource groups. It invokes the "claddres" utility # to make all specified changes to the given resource group. # Some changes can be passed in as their own, unique input to # this function, but the majority of eligible change parameters # arrive via the "attributes" hash, passed in by reference. # # Inputs: See the "devDoc()" function, above. # # Outputs: The properties hash is populated. The only other outputs are # any error messages that might be needed. # # Returns: Zero if no errors are detected. Otherwise, an appropriate # non-zero value is returned. Refer to the "RETURN" section # of the "devDoc()" function, above, for the standard return # code values/meanings for clmgr. # #============================================================================ function KLIB_HACMP_modify_resourcegroup { . $HALIBROOT/log_entry "$0()" "$CL" : version=@(#) df5e164 43haes/lib/ksh93/hacmp/KLIB_HACMP_modify_resourcegroup.sh, 726, 2147A_aha726, Apr 20 2021 10:49 PM : INPUTS: $* typeset -n properties=$1 typeset rg=${2//\"/} typeset -n attributes=$3 typeset mirror_group=$4 shift; shift; shift; shift typeset new_name=${1//\"/} typeset nodes=${2//\"/} typeset primarynodes=${3//\"/} typeset secondarynodes=${4//\"/} typeset site_policy=${5//\"/} typeset -u startup=${6//\"/} typeset -u fallover=${7//\"/} typeset -u fallback=${8//\"/} [[ $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 -i rc=$RC_UNKNOWN typeset -i i=0 typeset resources="FALLBACK_AT SERVICE_LABEL APPLICATIONS \ VOLUME_GROUP FORCED_VARYON VG_AUTO_IMPORT FILESYSTEM \ FSCHECK_TOOL RECOVERY_METHOD FS_BEFORE_IPADDR EXPORT_FILESYSTEM \ EXPORT_FILESYSTEM_V4 MOUNT_FILESYSTEM STABLE_STORAGE_PATH WPAR_NAME \ NFS_NETWORK SHARED_TAPE_RESOURCES DISK RAW_DISK AIX_FAST_CONNECT_SERVICES \ COMMUNICATION_LINKS WLM_PRIMARY WLM_SECONDARY MISC_DATA \ NODE_PRIORITY_POLICY NODE_PRIORITY_POLICY_SCRIPT \ NODE_PRIORITY_POLICY_TIMEOUT CONCURRENT_VOLUME_GROUP \ SDNP_SCRIPT_PATH SDNP_SCRIPT_TIMEOUT USERDEFINED_RESOURCES MANAGE_RDISK \ SVCPPRC_REP_RESOURCE SR_REP_RESOURCE GENXD_REP_RESOURCE TC_REP_RESOURCE \ DATA_DIVERGENCE_RECOVERY VARYON_WITH_MISSING_UPDATES PPRC_REP_RESOURCE" typeset policy_env="STARTUP FALLOVER FALLBACK SITE_POLICY" typeset attr= cmdargs= found= DATA="" typeset -A startupAry fallbackAry falloverAry rg_behavior startupAry=( [0]="OHN" [OHN]="OHN" [OFAN]="OFAN" [OAAN]="OAAN" [OUDP]="OUDP" ) fallbackAry=( [0]="FBHPN" [NFB]="NFB" [FBHPN]="FBHPN" ) falloverAry=( [0]="FNPN" [FNPN]="FNPN" [FUDNP]="FUDNP" [BO]="BO" ) typeset -A rgAttrs if [[ $rg != *([[:space:]]) ]]; then CL=$LINENO KLIB_HACMP_get_rg_attributes "$rg" rgAttrs (( $? != 0 )) && rc=RC_NOT_FOUND fi if (( $rc == $RC_NOT_FOUND )); then log_return_msg "$rc" "$0()" "$LINENO" return $? fi #=============================================== : Check for compatibility between the fallback : policy and the fallback timer setting. #=============================================== if [[ -n $fallback && $fallback == "NFB" ]]; then if [[ -n ${attributes[FALLBACK_AT]} ]]; then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 '\nERROR: conflicting options were provided, "%1$s" versus "%2$s".\n\n' "TIMER=${attributes[FALLBACK_AT]}" "FALLBACK=NFB" 1>&2 rc=$RC_INCORRECT_INPUT elif [[ -n ${rgAttrs[FALLBACK_AT]} ]] && \ [[ " ${!_ENV_ARGS[*]} " != *\ FALLBACK_AT\ * || \ -n ${attributes[FALLBACK_AT]} ]] then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 '\nERROR: conflicting options were provided, "%1$s" versus "%2$s".\n\n' "TIMER=${rgAttrs[FALLBACK_AT]}" "FALLBACK=NFB" 1>&2 rc=$RC_INCORRECT_INPUT fi elif [[ -n ${attributes[FALLBACK_AT]} && \ ${rgAttrs[FALLBACK]} == "NFB" && \ $fallback != "FBHPN" ]] then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 36 '\nERROR: conflicting options were provided, "%1$s" versus "%2$s".\n\n' "TIMER=${attributes[FALLBACK_AT]}" "FALLBACK=NFB" 1>&2 rc=$RC_INCORRECT_INPUT fi #================================================================= : If any of the concurrent resource group policies are specified : incompletely, fill in the missing policies for the customer. #================================================================= if [[ "$startup:$fallover:$fallback" == "OAAN::" ]] then fallover="BO" fallback="NFB" elif [[ "$startup:$fallover:$fallback" == ":BO:" ]] then startup="OAAN" fallback="NFB" fi if [[ $site_policy == +([[:space:]]) ]]; then site_policy= fi [[ $startup == +([[:space:]]) ]] && startup= [[ $fallover == +([[:space:]]) ]] && fallover= [[ $fallback == +([[:space:]]) ]] && fallback= if [[ $rg != *([[:space:]]) ]]; then [[ -z $startup ]] && startup=${rgAttrs[STARTUP]} [[ -z $fallover ]] && fallover=${rgAttrs[FALLOVER]} [[ -z $fallback ]] && fallback=${rgAttrs[FALLBACK]} fi nodes=${nodes//,/ } primarynodes=${primarynodes//,/ } if [[ -n $primarynodes ]]; then primarynodes="$primarynodes $nodes" else primarynodes="$nodes" fi secondarynodes=${secondarynodes//,/ } typeset nodelist="$nodes $primarynodes $secondarynodes" #================================================================ : Assuming an object was specified, see if it is a known object #================================================================ if [[ $rg != *([[:space:]]) ]]; then CL=$LINENO KLIB_HACMP_is_known_rg "$rg" (( $? != RC_SUCCESS )) && rc=$RC_NOT_FOUND fi typeset -i haveSites=0 print "$0()[$LINENO]($SECONDS): cllssite" >>$CLMGR_TMPLOG # Always log commands cllssite >/dev/null 2>&1 cmd_rc=$? print "$0()[$LINENO]($SECONDS): cllssite RC: $cmd_rc" >>$CLMGR_TMPLOG # Always log command result (( $cmd_rc == RC_SUCCESS )) && haveSites=1 #================= : Validate input #================= if [[ -z $rg ]]; 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" "$rg" 1>&2 /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 if [[ -n $new_name && -n "${new_name//[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_name" "${new_name//[a-zA-Z0-9_]/}" 1>&2 rc=$RC_INCORRECT_INPUT fi if [[ -n $startup && $startup != @(OHN|OFAN|OAAN|OUDP) ]]; then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\": \"%2\$s\".\n" STARTUP "$startup" 1>&2 /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "OHN, OFAN, OAAN, OUDP" 1>&2 rc=$RC_INCORRECT_INPUT fi if [[ -n $fallback && $fallback != @(NFB|FBHPN) ]]; then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\": \"%2\$s\".\n" FALLBACK "$fallback" 1>&2 /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "NFB, FBHPN" 1>&2 rc=$RC_INCORRECT_INPUT fi if [[ -n $fallover && $fallover != @(FNPN|FUDNP|BO) ]]; then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\": \"%2\$s\".\n" FALLOVER "$fallover" 1>&2 /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "FNPN, FUDNP, BO" 1>&2 rc=$RC_INCORRECT_INPUT fi if [[ -n $site_policy || -n $secondarynodes ]]; then if (( haveSites )); then case $site_policy in i*) ;; p*) site_policy=PPS ;; e*) site_policy=OES ;; b*) site_policy=OBS ;; *) if [[ -n $site_policy ]]; then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\": \"%2\$s\".\n" SITE_POLICY "$site_policy" 1>&2 /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "ignore, primary, either, both" 1>&2 rc=$RC_INCORRECT_INPUT fi ;; esac fi fi # : If nodes were specified, verify that they are known nodes. # if [[ $nodelist != *([[:space:]]) ]]; then typeset checked= typeset -i all_nodes_found=1 for node in ${nodelist//,/ }; do [[ " $checked " == *\ $node\ * ]] && continue checked="$checked $node" CL=$LINENO KLIB_HACMP_is_known_node "$node" >/dev/null 2>&1 if (( $? != RC_SUCCESS )); then rc=$RC_INCORRECT_INPUT all_nodes_found=0 /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$node" 1>&2 fi done if (( ! all_nodes_found )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 151 "Available Nodes:\n\n" 1>&2 typeset available CL=$LINENO KLIB_HACMP_list_nodes available for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" fi fi # : If disk error Management was specified, verify that its : value is yes or no only # if [[ ${attributes[MANAGE_RDISK]} != *([[:space:]]) ]]; then attributes[MANAGE_RDISK]=${attributes[MANAGE_RDISK]// /} #removing leading and trailing space if exist typeset err_manage=${attributes[MANAGE_RDISK]} if [[ $err_manage != @(yes|no) ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 110 "\nERROR: invalid value specified for \"%1\$s\": \"%2\$s\".\n" MANAGE_RDISK "$err_manage" 1>&2 dspmsg -s $CLMGR_SET $CLMGR_MSGS 3 "Valid values: %1\$s\n\n" "yes, no" 1>&2 rc=$RC_INCORRECT_INPUT fi fi # : If service IPS were specified, verify that they are known service IPs. # if [[ ${attributes[SERVICE_LABEL]} != *([[:space:]]) ]]; then typeset sip= sips=${attributes[SERVICE_LABEL]} sips=${sips//,/ } typeset -i all_sips_found=1 typeset FINAL_SIPS="" for sip in $sips; do typeset LABEL="" CL=$LINENO KLIB_HACMP_is_known_service_ip "$sip" LABEL >/dev/null 2>&1 if (( $? != RC_SUCCESS )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$sip" 1>&2 rc=$RC_INCORRECT_INPUT all_sips_found=0 elif [[ -n $LABEL && $sip != $LABEL ]]; then [[ -n $FINAL_SIPS ]] && FINAL_SIPS="$FINAL_SIPS " FINAL_SIPS="$FINAL_SIPS$LABEL" else [[ -n $FINAL_SIPS ]] && FINAL_SIPS="$FINAL_SIPS " FINAL_SIPS="$FINAL_SIPS$sip" fi done if (( ! all_sips_found )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 156 "Available Service IPs:\n\n" 1>&2 typeset available CL=$LINENO KLIB_HACMP_list_service_ip available for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" elif [[ -n $FINAL_SIPS ]]; then integer VALID_SI=1 typeset SI_RG="" attr="" for sip in $FINAL_SIPS; do #============================================ : Make sure that service IP $sip is not : assigned to more than one resource group. #============================================ SI_RG=$(clodmget -n -q "value=$sip AND name=SERVICE_LABEL" -f group HACMPresource) if [[ -n $SI_RG && $rg != $SI_RG ]]; then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1124 '\nERROR: the specified service label, "%1$s", is already in use by resource group "%2$s".\n\n' "$sip" "$SI_RG" 1>&2 rc=$RC_INCORRECT_INPUT VALID_SI=0 fi done (( VALID_SI )) && attributes[SERVICE_LABEL]=${FINAL_SIPS// /,} unset VALID_SI SI_RG attr fi fi # : If application controllers were specified, verify that they are : known application controllers. # if [[ ${attributes[APPLICATIONS]} != *([[:space:]]) ]]; then typeset app= apps=${attributes[APPLICATIONS]} apps=${apps//,/ } typeset -i all_apps_found=1 typeset -i app_count=0 typeset -i appmon_per_app_count=0 typeset -i appmon_count=0 for app in $apps; do appmon_per_app_count=0 CL=$LINENO KLIB_HACMP_is_known_appserver "$app" >/dev/null 2>&1 if (( $? != RC_SUCCESS )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$app" 1>&2 rc=$RC_INCORRECT_INPUT all_apps_found=0 else appmon_per_app_count=$(clodmget -q "name = RESOURCE_TO_MONITOR AND value = $app" -f monitor HACMPmonitor | wc -l) (( appmon_count += appmon_per_app_count )) (( app_count++ )) fi done if (( ! all_apps_found )); then 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 "" fi if (( $app_count > $MAX_USER_RESOURCES )) then #=========================================================================== : This check is added to stop the user if he adds more than specified limit : for application controllers in a resource group. The same code is used in : KLIB_HACMP_add_resourcegroup.sh. Any modifications here should also be : replicated in KLIB_HACMP_add_resourcegroup.sh. #=========================================================================== cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1444 "\nERROR: The number of configured %1\$s resources(%2\$d)\n\ has exceeded its maximum limit(%3\$d) per resource group.\n" "APPLICATION_CONTROLLER" "$app_count" "$MAX_USER_RESOURCES" rc=$RC_INCORRECT_INPUT fi if (( $appmon_count > $MAX_USER_RESOURCES )) then #=========================================================================== : This check is added to stop the user if he adds more than specified limit : for application monitors in a resource group. The same code is used in : KLIB_HACMP_add_resourcegroup.sh. Any modifications here should also be : replicated in KLIB_HACMP_add_resourcegroup.sh. #=========================================================================== cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1444 "\nERROR: The number of configured %1\$s resources(%2\$d)\n\ has exceeded its maximum limit(%3\$d) per resource group.\n" "APPLICATION_MONITOR" "$appmon_count" "$MAX_USER_RESOURCES" rc=$RC_INCORRECT_INPUT fi fi # : If volume groups were specified, verify that they are : known volume groups. # if [[ ${attributes[VOLUME_GROUP]} != *([[:space:]]) ]]; then typeset vg= vgs=${attributes[VOLUME_GROUP]//,/ } typeset -i all_vgs_found=1 typeset -i vg_count=0 for vg in $vgs; do CL=$LINENO KLIB_HACMP_is_known_volume_group "$vg" >/dev/null 2>&1 if (( $? != RC_SUCCESS )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 102 "\nERROR: \"%1\$s\" does not appear to exist!\n\n" "$vg" 1>&2 rc=$RC_INCORRECT_INPUT all_vgs_found=0 else (( vg_count++ )) fi done if (( ! all_vgs_found )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 160 "Available Volume Groups:\n\n" 1>&2 typeset available CL=$LINENO KLIB_HACMP_list_volume_groups available for (( i=0; i<${#available[*]}; i++ )); do if [[ ${available[$i]} != *([[:space:]]) ]]; then print -u2 "\t${available[$i]}" fi done print -u2 "" else #==================================================== : Make sure the correct VG type is used for this RG #==================================================== typeset vg_type="VOLUME_GROUP" [[ $startup == "OAAN" ]] && vg_type="CONCURRENT_VOLUME_GROUP" attributes[CONCURRENT_VOLUME_GROUP]="" attributes[VOLUME_GROUP]="" for vg in $vgs; do if [[ " ${attributes[$vg_type]} " != *\ $vg\ * ]]; then if [[ -n ${attributes[$vg_type]} ]]; then attributes[$vg_type]="${attributes[$vg_type]} " fi attributes[$vg_type]="${attributes[$vg_type]}$vg" #Checking the startup policy of Resource Group, If it is OAAN then check for VG containing #file system, if VG has fs throw the error. if [[ $startup == "OAAN" ]]; then vgfs=$(cl_showfs2 | awk '{print $2}' | grep -w $vg) if [[ -n $vgfs ]]; then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1458 "\nERROR: cannot add volume group \"%1\$s\" to OAAN(online on all available nodes) resource group \"%2\$s\"\n\ because \"%1\$s\" contains a file system.\n\n" "$vg" "$rg" 1>&2 rc=$RC_INCORRECT_INPUT fi fi fi done fi if (( $vg_count > $MAX_USER_RESOURCES )); then #=========================================================================== : This check is added to stop the user if he adds more than specified limit : for volume groups in a resource group. The same code is used in : KLIB_HACMP_add_resourcegroup.sh. Any modifications here should also be : replicated in KLIB_HACMP_add_resourcegroup.sh. #=========================================================================== cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1444 "\nERROR: The number of configured %1\$s resources(%2\$d)\n\ has exceeded its maximum limit(%3\$d) per resource group.\n" "VOLUME_GROUP" "$vg_count" "$MAX_USER_RESOURCES" rc=$RC_INCORRECT_INPUT fi elif [[ " ${!_ENV_ARGS[*]} " == *\ VOLUME_GROUP\ * ]]; then attributes[CONCURRENT_VOLUME_GROUP]="" attributes[VOLUME_GROUP]="" fi # : If file systems were specified, parse them and verify max limit # if [[ ${attributes[FILESYSTEM]} != *([[:space:]]) ]]; then typeset -i fs_count=0 fs_dup=0 typeset fs= fs_list= fs_type="FILESYSTEM" # convert comma separated list into space separated one fs_list=${attributes[$fs_type]//,/ } # Parse the provided FS list to find total FS count excluding duplicates(if any) # And, fill attributes[FILESYSTEM] with valid filesystems only attributes[$fs_type]="" for fs in $fs_list; do if [[ " ${attributes[$fs_type]} " != *\ $fs\ * ]]; then if [[ -n ${attributes[$fs_type]} ]]; then attributes[$fs_type]="${attributes[$fs_type]} " fi attributes[$fs_type]="${attributes[$fs_type]}$fs" (( fs_count++ )) else (( fs_dup++ )) fi done if (( $fs_dup > 0 )); then cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1442 "\nINFO: Found %1\$d duplicate entries in %2\$s list. Excluding them.\n" "$fs_dup" "$fs_type" fi if (( $fs_count > $MAX_USER_RESOURCES )); then #=========================================================================== : This check is added to stop the user if he adds more than specified limit : for file systems in a resource group. The same code is used in : KLIB_HACMP_add_resourcegroup.sh. Any modifications here should also be : replicated in KLIB_HACMP_add_resourcegroup.sh. #=========================================================================== cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1444 "\nERROR: The number of configured %1\$s resources(%2\$d)\n\ has exceeded its maximum limit(%3\$d) per resource group.\n" "$fs_type" "$fs_count" "$MAX_USER_RESOURCES" rc=$RC_INCORRECT_INPUT fi fi #======================================================= : If a secondary node has been specified, : makes sure a compatible cluster type has : also been set. #======================================================= if [[ -n $secondarynodes && \ $CLUSTER_TYPE == "NSC" ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1106 '\nERROR: "%1$s" may only be set for a stretched cluster or linked cluster.\n\n' "SECONDARYNODES" 1>&2 rc=$RC_INCORRECT_INPUT fi #================================================== : If a site policy has been specified, : makes sure a compatible cluster type has : also been set. #================================================== if [[ -n $site_policy && \ $CLUSTER_TYPE == "NSC" ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1106 '\nERROR: "%1$s" may only be set for a stretched cluster or linked cluster.\n\n' "SITE_POLICY" 1>&2 rc=$RC_INCORRECT_INPUT fi #================================================ : If a node priority policy has been specified, : makes sure a compatible fallover policy has : also been set. #================================================ if [[ ${attributes[NODE_PRIORITY_POLICY]} != *([[:space:]]) && \ ${attributes[NODE_PRIORITY_POLICY]} != "default" && \ $fallover != "FUDNP" ]] then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 230 "\nERROR: a node priority policy may only be used with a fallover policy\n of \"FUDNP\" (\"Fallover Using Dynamic Node Priority\").\n\n" 1>&2 rc=$RC_INCORRECT_INPUT fi #================================================ : If a node priority policy script has been specified, : make sure a compatible fallover policy has : also been set. #================================================ if [[ ${attributes[NODE_PRIORITY_POLICY_SCRIPT]} != *([[:space:]]) && \ ${fallover[${rg_behavior[fallover]}]} != "FUDNP" ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1177 '\nERROR: Node priority policy script is only used with a fallover policy\nof "FUDNP" ("Fallover Using Dynamic Node Priority").\n\n' 1>&2 rc=$RC_INCORRECT_INPUT fi #================================================ : If a node priority policy timeout has been specified, : make sure a compatible fallover policy has : also been set. #================================================ if [[ ${attributes[NODE_PRIORITY_POLICY_TIMEOUT]} != *([[:space:]]) && \ ${fallover[${rg_behavior[fallover]}]} != "FUDNP" ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1178 '\nERROR: Node priority policy timeout is only used with a fallover policy\nof "FUDNP" ("Fallover Using Dynamic Node Priority").\n\n' 1>&2 rc=$RC_INCORRECT_INPUT fi #================================================ : If fallover policy is DNP, : make sure a Node priority policy has : also been set. #================================================ if [[ ${attributes[NODE_PRIORITY_POLICY]} == *([[:space:]]) && ${rgAttrs[NODE_PRIORITY_POLICY]} == *([[:space:]]) && \ ${fallover[${rg_behavior[fallover]}]} == "FUDNP" ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1220 '\nERROR: Node priority policy should be specified with a fallover policy\nof "FUDNP" ("Fallover Using Dynamic Node Priority") is used.\n\n' 1>&2 rc=$RC_INCORRECT_INPUT fi #======================================================= : If Node priority policy has been specified as default : then make sure no Node priority policy script is set #======================================================= if [[ ${attributes[NODE_PRIORITY_POLICY]} == "default" && ${attributes[NODE_PRIORITY_POLICY_SCRIPT]} != *([[:space:]]) ]] then dspmsg -s $CLMGR_SET $CLMGR_MSGS 1224 '\nERROR: when Node priority policy is specified as default, Node priority policy script should not be provided. \n\n' 1>&2 rc=$RC_INCORRECT_INPUT fi #==================================================================== : If any raw disks have been specified, make sure they are valid, : and convert them to their PVIDs, as required by the base product. #==================================================================== if [[ -n ${attributes[DISK]} ]]; then attributes[DISK]=${attributes[DISK]#,} attributes[DISK]=${attributes[DISK]//,/ } typeset disk="" new_disks="" for disk in ${attributes[DISK]}; do typeset IDENTIFIERS="" CL=$LINENO getDiskData "$disk" "$nodes" IDENTIFIERS if (( $? == RC_SUCCESS )) && [[ -n $IDENTIFIERS ]]; then typeset NAME="" PVID="" UUID="" REM="" print -- "$IDENTIFIERS" | IFS=: read NAME PVID UUID REM if [[ $disk == $PVID ]]; then if [[ -n $new_disks ]]; then if [[ $new_disks == *\-* ]]; then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1128 '\nERROR: raw disks may be specified as PVIDs or UUIDs (or device names, which get converted to UUIDs), but not both.\n\n' 1>&2 rc=$RC_INCORRECT_INPUT break fi new_disks="$new_disks " fi new_disks="$new_disks$PVID" elif [[ -n $UUID ]]; then if [[ $disk != $UUID ]]; then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1129 '*** Warning: automatically converting "%1$s" to its UUID, "%2$s".\n' "$disk" "$UUID" fi if [[ -n $new_disks ]]; then if [[ $new_disks != *\-* ]]; then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1130 '\nERROR: raw disks may be specified as PVIDs or UUIDs, but not both.\n\n' 1>&2 rc=$RC_INCORRECT_INPUT break fi new_disks="$new_disks " fi new_disks="$new_disks$UUID" fi else rc=$RC_INCORRECT_INPUT fi done # End of the raw disk loop if [[ -n $new_disks ]]; then if [[ $new_disks == *-* ]]; then attributes[RAW_DISK]=$new_disks attributes[DISK]="" else attributes[DISK]=$new_disks attributes[RAW_DISK]="" fi fi fi #===================================================================== : If a node priority policy of "least" or "most" has been specified, : makes sure a valid policy script has also been specified. #===================================================================== if [[ ${attributes[NODE_PRIORITY_POLICY]} != *([[:space:]]) && \ ${attributes[NODE_PRIORITY_POLICY]} == *@(least|most|udscript)* ]]; then typeset nppScript=${attributes[NODE_PRIORITY_POLICY_SCRIPT]} nppScript=${nppScript%%+([[:space:]])*} if [[ -z $nppScript || ! -f $nppScript ]]; then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 231 "\nERROR: a node priority policy of \"least\" or \"most\" requires\n an associated, valid script to be specified using the\n \"NODE_PRIORITY_POLICY_SCRIPT\" option.\n\n" 1>&2 rc=$RC_INCORRECT_INPUT else attributes[SDNP_SCRIPT_PATH]=${attributes[NODE_PRIORITY_POLICY_SCRIPT]} unset attributes[NODE_PRIORITY_POLICY_SCRIPT] attributes[SDNP_SCRIPT_TIMEOUT]=${attributes[NODE_PRIORITY_POLICY_TIMEOUT]} unset attributes[NODE_PRIORITY_POLICY_TIMEOUT] fi fi if [[ ${attributes[NODE_PRIORITY_POLICY_SCRIPT]} != *([[:space:]]) ]]; then attributes[SDNP_SCRIPT_PATH]=${attributes[NODE_PRIORITY_POLICY_SCRIPT]} unset attributes[NODE_PRIORITY_POLICY_SCRIPT] fi if [[ ${attributes[NODE_PRIORITY_POLICY_TIMEOUT]} != *([[:space:]]) ]]; then attributes[SDNP_SCRIPT_TIMEOUT]=${attributes[NODE_PRIORITY_POLICY_TIMEOUT]} unset attributes[NODE_PRIORITY_POLICY_TIMEOUT] fi if [[ -n ${attributes[NODE_PRIORITY_POLICY]} ]]; then case "${attributes[NODE_PRIORITY_POLICY]}" in cpu) attributes[NODE_PRIORITY_POLICY]=cl_highest_idle_cpu ;; disk) attributes[NODE_PRIORITY_POLICY]=cl_lowest_disk_busy ;; mem) attributes[NODE_PRIORITY_POLICY]=cl_highest_free_mem ;; least) attributes[NODE_PRIORITY_POLICY]=cl_lowest_nonzero_udscript_rc ;; most) attributes[NODE_PRIORITY_POLICY]=cl_highest_udscript_rc ;; cl_*) ;; # Use as-is *) attributes[NODE_PRIORITY_POLICY]=""; esac fi if [ "${fallover}" != "${falloverAry[FUDNP]}" ]; then attributes[NODE_PRIORITY_POLICY]="" attributes[SDNP_SCRIPT_PATH]="" attributes[SDNP_SCRIPT_TIMEOUT]="" fi #================================================================== : If a WPAR was specified, its name must match the name of the RG #================================================================== if (( $rc == RC_UNKNOWN )); then if [[ ${attributes[WPAR_NAME]} != *([[:space:]]) ]]; then if [[ $new_name == *([[:space:]]) && \ ${attributes[WPAR_NAME]} != $rg ]] then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1125 '\nERROR: the specified WPAR_NAME, "%1$s", does not match the resource group name, "%2$s".\n\n' "${attributes[WPAR_NAME]}" "$rg" 1>&2 rc=$RC_INCORRECT_INPUT elif [[ $new_name != *([[:space:]]) && \ ${attributes[WPAR_NAME]} != $new_name ]] then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1126 '\nERROR: the specified WPAR_NAME, "%1$s", does not match the new name of the resource group, "%2$s".\n\n' "${attributes[WPAR_NAME]}" "$new_name" 1>&2 rc=$RC_INCORRECT_INPUT fi elif [[ $new_name != *([[:space:]]) ]]; then : Make any current WPAR_NAME match the new RG name if [[ ${rgAttrs[WPAR_NAME]} != *([[:space:]]) ]]; then CL=$LINENO cl_dspmsg -s $CLMGR_SET $CLMGR_MSGS 1127 '\nWarning: since resource group "%1$s" is being renamed to "%2$s", and has a WPAR defined, that WPAR will also be renamed to "%2$s". This is necessary because the WPAR attribute of a resource group, if used, is required to match the name of the resource group.' "$rg" "$new_name" attributes[WPAR_NAME]=$new_name fi fi fi if (( $rc == RC_UNKNOWN )); then #============================== : Construct the option string #============================== for attr in ${!attributes[*]}; do typeset -i found=0 for resource in $resources; do if [[ $attr == $resource ]]; then found=1 break fi done if (( ! found )); then rc=$RC_MISSING_INPUT break fi if [[ $attr == @(SERVICE_LABEL|APPLICATIONS|VOLUME_GROUP|DISK|RAW_DISK|FILESYSTEM|EXPORT_FILESYSTEM|EXPORT_FILESYSTEM_V4|MOUNT_FILESYSTEM|USERDEFINED_RESOURCES|PPRC_REP_RESOURCE) ]] then attributes[$attr]=${attributes[$attr]#,} attributes[$attr]=${attributes[$attr]//,/ } elif [[ $attr == @(SVCPPRC_REP_RESOURCE|SR_REP_RESOURCE|GENXD_REP_RESOURCE|TC_REP_RESOURCE) ]] #handling smit mirror group variables here then attributes[$attr]=${attributes[$attr]#,} attributes[$attr]=${attributes[$attr]//,/ } mirror_group="${mirror_group}${mirror_group:+ }${attributes[$attr]}" continue fi cmdargs="$cmdargs $attr=${attributes[$attr]}" done if [[ $mirror_group != *([[:space:]]) ]]; then #=================================================== : Determine the type of the mirror group, then add : the appropriate argument to the command string. #=================================================== for each_mirror_group in $(echo $mirror_group | sed "s/,/ /g") #if we have more than one mirror group do typeset -A mgProps CL=$LINENO KLIB_HACMP_get_mirror_group_attributes "$each_mirror_group" mgProps if (( $? == 0 )); then case "${mgProps[TYPE]}" in emc) SR_REP_RESOURCE="$SR_REP_RESOURCE $each_mirror_group" ;; hit*) TC_REP_RESOURCE="$TC_REP_RESOURCE $each_mirror_group" ;; svc) SVCPPRC_REP_RESOURCE="$SVCPPRC_REP_RESOURCE $each_mirror_group" ;; *) GENXD_REP_RESOURCE="$GENXD_REP_RESOURCE $each_mirror_group" ;; esac else rc=$RC_INCORRECT_INPUT fi done if (( $rc != $RC_INCORRECT_INPUT )); then cmdargs="$cmdargs SR_REP_RESOURCE=$SR_REP_RESOURCE TC_REP_RESOURCE=$TC_REP_RESOURCE SVCPPRC_REP_RESOURCE=$SVCPPRC_REP_RESOURCE GENXD_REP_RESOURCE=$GENXD_REP_RESOURCE" fi elif [[ " ${!_ENV_ARGS[*]} " == *\ MIRROR_GROUP\ * ]]; then : Customer wants to remove mirror group from $rg cmdargs="$cmdargs SVCPPRC_REP_RESOURCE= SR_REP_RESOURCE= TC_REP_RESOURCE= GENXD_REP_RESOURCE=" fi #===================================================================== : The "claddres" command takes the incoming resource list as a : replacement list instead of a delta list, at least for replicated : resources. So it is necessary to pass in all current, replicated : settings, if they are not part of the users specified change list, : to avoid having those settings get mistakenly erased. #===================================================================== print "$0()[$LINENO]($SECONDS): LC_ALL=C LANG=C cllsres -g \"$rg\"" >>$CLMGR_TMPLOG # Always log commands # LC_ALL and LANG set to C, to avoid changing ODM data with non-english text. DATA=$(LC_ALL=C LANG=C cllsres -g "$rg") print "$0()[$LINENO]($SECONDS): LC_ALL=C LANG=C cllsres RC: $?" >>$CLMGR_TMPLOG # Always log command result print -- "$DATA" |\ while IFS="=" read name value rem; do [[ -z $name || -z $value ]] && continue [[ " ${!attributes[*]} " == *\ $name\ * ]] && continue [[ " $cmdargs" == *\ $name=* ]] && continue value=${value//\"/} cmdargs="$cmdargs $name=$value" done #=========================================================== : Add the remaining, empty fields. Doing this because the : SMIT panel does it, and this code needs to be identical. #=========================================================== for name in $resources; do if [[ " $cmdargs" != *\ $name=* ]]; then cmdargs="$cmdargs $name=" fi done fi #================================================================== : Modify the resource group if no input errors have been detected #================================================================== if (( $rc == RC_UNKNOWN )); then if [[ "$new_name $nodes $site_policy $startup $fallover $fallback" != +([[:space:]]) ]]; then typeset Gopt= Nopt= Sopt= Oopt= Bopt sopt= [[ -n $new_name ]] && Gopt=" -G $new_name" [[ -n $nodes ]] && Nopt=" -n \"$nodes\"" [[ -n $startup ]] && Sopt=" -S ${startup[${rg_behavior[startup]}]}" [[ -n $fallover ]] && Oopt=" -O ${fallover[${rg_behavior[fallover]}]}" [[ -n $fallback ]] && Bopt=" -B ${fallback[${rg_behavior[fallback]}]}" if (( haveSites )); then if [[ -n $primarynodes && -z $secondarynodes ]] || \ [[ -z $primarynodes && -n $secondarynodes ]] then typeset -A rgAttrs CL=$LINENO KLIB_HACMP_get_resourcegroup_state "$rg" rgAttrs if [[ -z $primarynodes ]]; then primarynodes=${rgAttrs[PRIMARYNODES]} fi if [[ -z $secondarynodes ]]; then secondarynodes=${rgAttrs[SECONDARYNODES]} fi fi [[ -n $primarynodes ]] && yopt=" -y \"$primarynodes\"" [[ -n $secondarynodes ]] && zopt=" -z \"$secondarynodes\"" [[ -n $site_policy ]] && sopt=" -s $site_policy" fi print "$0()[$LINENO]($SECONDS): clchgrp -g \"$rg\"$Gopt$Nopt$Sopt$Oopt$Bopt$sopt$yopt$zopt" >>$CLMGR_TMPLOG # Always log commands eval "clchgrp -g \"$rg\"$Gopt$Nopt$Sopt$Oopt$Bopt$sopt$yopt$zopt" rc=$? print "$0()[$LINENO]($SECONDS): clchgrp RC: $rc" >>$CLMGR_TMPLOG # Always log command result if (( $rc != RC_SUCCESS )); then /usr/bin/dspmsg -s $CLMGR_SET $CLMGR_MSGS 400 "\nERROR: failed to modify \"%1\$s\".\n\n" "$rg" 1>&2 rc=$RC_ERROR elif [[ -n $new_name ]]; then rg=$new_name fi fi fi if (( $rc == RC_SUCCESS )); then if [[ $cmdargs != *([[:space:]]) ]]; then print "$0()[$LINENO]($SECONDS): claddres -g \"$rg\" $(echo \"$cmdargs\")" >>$CLMGR_TMPLOG # Always log commands claddres -g "$rg" $(echo "$cmdargs") >>$CLMGR_TMPLOG 2>$TMPDIR/clmgr.KHmrg.err.$$ rc=$? print "$0()[$LINENO]($SECONDS): claddres RC: $rc" >>$CLMGR_TMPLOG # Always log command result if [[ -s $TMPDIR/clmgr.KHmrg.err.$$ ]]; then #======================================================= : Convert internal variable names to match clmgr names #======================================================= typeset PAIR="" INNER="" OUTER="" for PAIR in SDNP_SCRIPT_PATH:NODE_PRIORITY_POLICY_SCRIPT \ SDNP_SCRIPT_TIMEOUT:NODE_PRIORITY_POLICY_TIMEOUT do print -- "$PAIR" | IFS=: read INNER OUTER REST sed "s/$INNER/$OUTER/g" $TMPDIR/clmgr.KHmrg.err.$$ > $TMPDIR/clmgr.KHmrg.err2.$$ mv -f $TMPDIR/clmgr.KHmrg.err2.$$ $TMPDIR/clmgr.KHmrg.err.$$ done cat $TMPDIR/clmgr.KHmrg.err.$$ 1>&2 rm -f $TMPDIR/clmgr.KHmrg.err.$$ fi if (( $rc != RC_SUCCESS )); then dspmsg -s $CLMGR_SET $CLMGR_MSGS 400 '\nERROR: failed to modify "%1$s".\n\n' "$rg" 1>&2 rc=$RC_ERROR fi fi fi #=========================================================== : If output from this operation was requested, retrieve it #=========================================================== if (( $rc == RC_SUCCESS )); then [[ -n $new_name ]] && name=$new_name if (( CLMGR_VERBOSE )) || [[ -n $CLMGR_ATTRS ]]; then CL=$LINENO KLIB_HACMP_get_rg_attributes "$rg" 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 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 resource_group -h" "RESOURCE GROUP:" "$CLMGR_PROGNAME" 1>&2 fi log_return_msg "$rc" "$0()" "$LINENO" return $? } # End of "KLIB_HACMP_modify_resourcegroup()" #============================================================================ # # Name: devDoc # # Description: This is a never-to-be-called, wrapper function that all the # clmgr FPATH functions implement in order to hide embedded # syntax from trace logging. This information is implemented # in POD format, and can be viewed in a number of ways using # POD tools. Some viewing suggestions for this function's POD- # formatted information are: # # perldoc # pod2text -c # pod2text -c --code # pod2html # # However, the more important use for this information is that # it is parsed by clmgr to display the syntax for this file's # operation. The information in the "SYNOPSIS" section is used # for this purpose. This feature was originally implemented # using the man page information. However, in a code review it # was pointed out that this approach had to be changed because # customers do not have to install the man pages! Therefore, a # built-in dependency on man page information would break the # automatic help feature of clmgr. So the SYNPOSIS section must # be used instead. # # IMPORTANT: As a result of this, it is imperative that the # information in this SYNOPSIS be kept in sync # with the man page information, which is owned # by the IDD team. # # Inputs: None. # # Outputs: None. # # Returns: n/a (not intended to be invoked) # #============================================================================ function devDoc { : <<'=cut' >/dev/null 2>&1 =head1 NAME KLIB_HACMP_modify_resourcegroup =head1 SYNOPSIS clmgr modify resource_group \ [ NAME= ] \ [ NODES=nodeA1[,nodeA2,...] ] \ [ SECONDARYNODES=nodeB2[,nodeB1,...] ] \ [ SITE_POLICY={ignore|primary|either|both} ] \ [ STARTUP={OHN|OFAN|OAAN|OUDP} ] \ [ FALLOVER={FNPN|FUDNP|BO} ] \ [ FALLBACK={NFB|FBHPN} ] \ [ NODE_PRIORITY_POLICY={default|mem|cpu| \ disk|least|most} ] \ [ NODE_PRIORITY_POLICY_SCRIPT= ] \ [ NODE_PRIORITY_POLICY_TIMEOUT=### ] \ [ SERVICE_LABEL=service_ip#1[,service_ip#2,...] ] \ [ APPLICATIONS=appctlr#1[,appctlr#2,...] ] \ [ VOLUME_GROUP=[,,...] ] \ [ FORCED_VARYON={true|false} ] \ [ VG_AUTO_IMPORT={true|false} ] \ [ FILESYSTEM=/file_system#1[,/file_system#2,...] ] \ [ DISK=[,,...] ] \ [ FS_BEFORE_IPADDR={true|false} ] \ [ WPAR_NAME="wpar_name" ] \ [ EXPORT_FILESYSTEM=/expfs#1[,/expfs#2,...] ] \ [ EXPORT_FILESYSTEM_V4=/expfs#1[,/expfs#2,...] ] \ [ STABLE_STORAGE_PATH="/fs3" ] \ [ NFS_NETWORK="nfs_network" ] \ [ MOUNT_FILESYSTEM=/nfs_fs1;/expfs1,/nfs_fs2;,... ] \ [ MIRROR_GROUP= ] \ [ FALLBACK_AT= ] \ [ MANAGE_RDISK={yes|no} ] \ [ USERDEFINED_RESOURCES=/resource#1[,/resource#2,...] ] NOTE: the FALLBACK_AT parameter is only valid if the FALLBACK policy is not "NFB". An alias of "TIMER" may be used. STARTUP: OHN ----- Online Home Node (default value) OFAN ---- Online on First Available Node OAAN ---- Online on All Available Nodes (concurrent) OUDP ---- Online Using Node Distribution Policy FALLBACK: NFB ----- Never Fallback FBHPN --- Fallback to Higher Priority Node (default value) FALLOVER: FNPN ---- Fallover to Next Priority Node (default value) FUDNP --- Fallover Using Dynamic Node Priority BO ------ Bring Offline (On Error Node Only) NODE_PRIORITY_POLICY: NOTE: this policy may only be established if if the FALLOVER policy has been set to "FUDNP". default - next node in the NODES list mem ----- node with most available memory disk ---- node with least disk activity cpu ----- node with most available CPU cycles least --- node where the dynamic node priority script returns the lowest value most ---- node where the dynamic node priority script returns the highest value SITE_POLICY: ignore -- Ignore primary - Prefer Primary Site either -- Online On Either Site both ---- Online On Both Sites NOTE: "SECONDARYNODES" and "SITE_POLICY" only apply when sites are configured within the cluster. NOTE: the alias for "resource_group" is "rg". =head1 DESCRIPTION Attempts to modify the specified resource group 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. rgname [REQUIRED] [string] The label of the resource group that is to be modified. 3. attributes [OPTIONAL] [hash ref] An associative array that contains modification parameters for the resource group. 4. mirror_group [OPTIONAL] [string] A replicated resource that is to be managed by this resource group. 5. new_name [OPTIONAL] [string] A new label to apply to the specified resource group. 6. nodes [OPTIONAL] [string] A new list of nodes that the specified resource group will be managed on. 7. primarynodes [OPTIONAL] [string] A new list of primary nodes for the specified resource group (only valid when sites are in use). 8. secondarynodes [OPTIONAL] [string] A new list of secondary nodes for the specified resource group (only valid when sites are in use). 9. site_policy [OPTIONAL] [string] A new site policy to be applied to the specified resource group (if sites are configured in this cluster), from the valid set {ignore|primary|either|both}. 10. startup [OPTIONAL] [string] A new startup policy to apply to the specified resource group, from the valid set {OHN|OFAN|OAAN|OUDP}. 11. fallover [OPTIONAL] [string] A new fallover policy to apply to the specified resource group, from the valid set {FNPN|FUDNP|BO}. 12. fallback [OPTIONAL] [string] A new fallback policy to apply to the specified resource group, from the valid set {NFB|FBHPN}. =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 "devDoc()" #============================================================================== # The following, comment block attempts to enforce coding standards when this # file is edited via emacs or vim. This block _must_ appear at the very end # of the file, or the editor will not find it, and it will be ignored. #============================================================================== # Local Variables: # indent-tabs-mode: nil # tab-width: 4 # End: #============================================================================== # vim: tabstop=4 shiftwidth=4 expandtab #==============================================================================