#!/usr/bin/ksh93
#  ALTRAN_PROLOG_BEGIN_TAG
#  This is an automatically generated prolog.                                  
#                                                                              
#  Copyright (C) Altran ACT S.A.S. 2019,2021.  All rights reserved.  
#                                                                              
#  ALTRAN_PROLOG_END_TAG
#  @(#)  7d4c34b 43haes/usr/sbin/cluster/sa/filenet/sbin/cl_filenet_db_ce_pe_import.sh, 726, 2147A_aha726, Feb 05 2021 09:50 PM
#                                                                              
# IBM_PROLOG_BEGIN_TAG 
# This is an automatically generated prolog. 
#  
# Licensed Materials - Property of IBM 
#  
# COPYRIGHT International Business Machines Corp. 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 
#-----------------------------------------------------------------------------
#
# Name: cl_filenet_db_ce_pe_import
#
# DB2 Smart Assist import function for adding and removing HACMP resources.
#
# Syntax:
# cl_filenet_db_ce_pe_import [-D | -v] [-M] {-a | -r} -o <InstanceOwningNode>
#				-n <TakeoverNode1[:TakeoverNode2...]>
#    				-i <InstanceOwner>
#				-d <DatabaseName>
#				-l <ServiceLabel>
#				-w <IP_Network>
# 
# Arguments:
#	-C 	Component ID 
#
#	-D	Turn on debug mode.
#
#	-A	Application Name - Smart assistant application identifier
#
#	-v	Turn on verbose mode.
#
#	-a	Add/change all necessary HACMP resources for the specified DB2 instance.
#		If the resources already exist, they will be removed and then added.
#		This is the change/modify mode.
#
#	-r	Remove all HACMP resources for the specified DB2 instance.
#
#	-o	DB2 UDB instance owning node.  This is the node that has the
#		highest priority.
#
#	-n	DB2 UDB takeover node(s).  These nodes will be appended to the
#		instance owning	node and then passed to "claddgrp -n".  Takeover
#		nodelist is colon-separated.
#
#	-i	DB2 UDB instance name (owner) to be made highly available or
#		removed.  This is the only option required when removing (-r)
#		the resources.
#
#	-d	DB2 UDB database name.  This database is used by the
#		Custom SQL Monitor.
#
#	-l	The TCP/IP service IP label used by DB2 to communicate with 
#		other application tiers and/or clients.
#
#	-w	The HACMP IP-based network where the service IP label (-l) is on.
#
# 	-M	Delete pre-existing configuration (modify mode)
#
# Returns:
#	0 on Success (import completed without error)
#	1 on Warning (import completed with warning(s))
#	2 on Failure (import failed due to pre-verification failure)
#	3 on Failure (import failed due to failure in adding resource)
# 
#-----------------------------------------------------------------------------

. /usr/es/lib/ksh93/func_include
version='1.1 $Source: 61haes_r711 43haes/usr/sbin/cluster/sa/filenet/sbin/cl_filenet_db_ce_pe_import.sh 2$'

#-----------------------------------------------------------------------------
# Global Definitions:
#-----------------------------------------------------------------------------

RECOVERY_ODM=/tmp/cl_db_ce_pe_import_RemRes_recovery_odm
RECOVERY_CMDS=/tmp/cl_db_ce_pe_import_RemRes_recovery_cmds

typeset -A MSGS
MSGS=(
	[1,3]="INFO: Verifying DB2 instance owner %s.\n"
	[1,4]="ERROR: DB2 instance owner (%s) does not exist!\n"
	[1,5]="ERROR: DB2 instance discovery data required but not found!\n"
	[1,6]="INFO: Sourcing in DB2 instance discovery data.\n"

	[2,2]="INFO: Verifying the existance of DB2 instance.\n"
	[2,3]="ERROR: The DB2 instance %s does not seem to be available!\n"
    	[2,4]="ERROR: A DB2 instance must be properly configured for instance owner %s!\n"
	[2,5]="INFO: Verifying the database to be monitored by the custom SQL monitor.\n"
	[2,6]="ERROR: Database %s does not seem to be available for custom SQL monitoring!\n"
	[2,7]="INFO: Verifying the correctness of the owning node.\n"
	[2,8]="ERROR: The instance owning node (%s) cannot be in the takeover node(s) (%s) list!\n"
	[2,9]="INFO: Verifying all supplied nodes are valid HACMP nodes.\n"
	[2,10]="ERROR: Node %s is not a cluster node!\n"
	[2,11]="ERROR: Both instance owning node and takeover node(s) must be cluster nodes!\n"
	[2,12]="ERROR: Function AddResources failed!\n"
	[2,14]="ERROR: Unexpected DB2 import action encountered!\n"
	[2,15]="ERROR: Failed cleaning up existing resources!\n"
    	[2,16]="ERROR: No resources have been added!\n"
	[2,17]="ERROR: Failed creating HACMP Application Server for instance %s!\n"
	[2,20]="ERROR: Failed adding HACMP SQL Monitor to the Meta Database!\n"
	[2,21]="ERROR: Failed creating HACMP Process Monitor for instance %s!\n"
	[2,22]="ERROR: Failed adding HACMP Process Monitor to the Meta Database!\n"
	[2,23]="ERROR: Failed creating HACMP Resource Group for instance %s!\n"
	[2,24]="ERROR: Failed updating HACMP Resource Group for instance %s!\n"
	[2,25]="ERROR: Failed adding HACMP Resource Group to the Meta Database!\n"

	[2,30]="ERROR: Failed removing DB2 Instance Application Server from HACMP!\n"
	[2,31]="ERROR: Failed removing DB2 Instance Resource Group from HACMP!\n"

	[2,32]="HACMP network %s is not enable for IPAT via IP Aliases!\n"
	[2,33]="ERROR: Function CheckInputs failed!\n"


	[2,39]="WARNING: The DB Instance Application Server does not exist in HACMP!\n"
	[2,40]="INFO: The DB2 Instance Resource Group does not exist in HACMP!\n"
	[2,41]="ERROR: Failed creating SQL Monitor hard link for %s on node %s!\n"
	[2,42]="ERROR: Failed stopping the DB2 instance %s on node %s!\n"
	[2,43]="INFO: Stopping instance %s on node %s!\n"
	[2,44]="WARNING: Instance %s on node %s is still running!\n"
	[2,45]="INFO: Sleeping for %s seconds (up to a total of %s seconds)...\n"
	[2,46]="INFO: Instance %s on node %s is stopped!\n"
	[2,47]="ERROR: Instance %s on node %s should be manually stopped before continuing!\n"
	[2,48]="INFO: Instance %s is not running on any node!\n"
	[2,49]="ERROR: Missing required argument(s) to import!\n"
	[2,50]="ERROR: Failed adding DATABASE_TO_MONITOR to the Meta Database!\n"
	[2,53]="ERROR: Failed creating HACMP Service IP Label for instance %s!\n"
	[2,57]="ERROR: Failed removing DB2 Instance Service IP Label from HACMP!\n"
	[2,58]="WARNING: The DB2 Instance Service IP Label does not exist in HACMP!\n"
	[2,59]="ERROR: The DB2 instance selected: %s is already defined to the HACMP\n\
cluster configuration with application: %s.\n"
)

PROGNAME=$(basename ${0})
PATH="$($(dirname ${0})/../../../utilities/cl_get_path all)"
PATH=$PATH:/usr/bin:/etc:/usr/sbin:/usr/ucb:/sbin:/usr/es/sbin/cluster/sa/sbin
FPATH_BASE=/usr/es/lib/ksh93
FPATH=$FPATH_BASE/hacmp:$FPATH_BASE/sa:$FPATH_BASE/db2:$FPATH_BASE/aix:\
$FPATH_BASE/aix/odm:$FPATH_BASE/db2/vg:$FPATH_BASE/util:$FPATH_BASE/util/list
export PATH FPATH
export ODMDIR=/etc/objrepos

export DB2SA_HOME="/usr/es/sbin/cluster/sa/db2"
export DB2SA_ETC_PATH="$DB2SA_HOME/etc"
export DB2SA_SBIN_DIR="$DB2SA_HOME/sbin"
export DB2SA_DISC_FILE="$DB2SA_ETC_PATH/db2.disc"

export DEBUG=${DEBUG:-"0"}
export VERBOSE=${VERBOSE:-"0"}
export ADD_RESOURCES=0
export REMOVE_RESOURCES=0
export INSTANCE_OWNING_NODE=""
export TAKEOVER_NODES=""
export INSTANCE_NAME=""

# same as DATABASE_TO_MONITOR
export DATABASE_NAME=""		
export SERVICE_LABEL=""
export IP_NETWORK=""
export DB2SALOG="/var/hacmp/log/db2sa.log"
export DB2SACAT="db2sa.cat"

# Add or Remove
export ACTION=""		

NUM_ARGS=$#
MODIFY_MODE=false
RG=""

#-----------------------------------------------------------------------------
#
# Name: usage
#
# Prints usage message and exits the program.
#
# Arguments:  none
#
# Global Variables:
#	DB2SACAT
#
# Returns:    does not return
#
function usage {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    dspmsg -s 10 filenetsa.cat 2 "Usage: cl_filenet_db_ce_pe_import [-D | -v] {-a | -r} -o <InstanceOwningNode>\n\
\t-n <TakeoverNode1[:TakeoverNode2...]> -i <InstanceOwner>\n\
\t-d <DatabaseName> -l <ServiceLabel> -w <IP_Network> [-M] [-F | -S]\n\
\n\
    -D	Turn on debug mode.\n\
    -v	Turn on verbose mode.\n\
    -a	Add/change all necessary HACMP resources for the specified DB2 instance.\n\
	If the resources already exist, they will be removed and then added.\n\
	This is the change/modify mode.\n\
    -r	Remove all HACMP resources for the specified DB2 instance.\n\
    -o	DB2 UDB instance owning node.  This is the node that has the highest priority.\n\
    -n	DB2 UDB takeover node(s).  These nodes will be appended to the instance\n\
	owning node and then passed to \"claddgrp -n\".  Takeover nodelist is colon-separated.\n\
    -i	DB2 UDB instance name (owner) to be made highly available or removed.  This is the\n\
	only option required when removing (-r) the resources.\n\
    -d	DB2 UDB database name.  This database is used by the Custom SQL Monitor.\n\
    -l	The TCP/IP service IP label used by DB2 to communicate with other application\n\
	tiers and/or clients.\n\
    -w	The HACMP IP-based network where the service IP label (-l) is on.\n\
    -M  Delete the pre-existing configuration (modify mode)\n\
    -F  Signal First Resource Group with respect to Mutual takeover configuration.\n\
    -S  Signal Second Resource Group with respect to Mutual takeover configuration.\n"

    exit 1
}

function errmsg {
	[[ "$VERBOSE_LOGGING" == "high" ]] && set -x
	typeset set=$1
	typeset id=$2
	shift
	shift
	KLIB_DB2_print_message $set $id "${MSGS[$set,$id]}" $*
}


#-----------------------------------------------------------------------------
# Name: RemoveResources
#
# Description:
# 		Removes (-r) HACMP resources for DB2 Smart Assist.  This function
#		removes all the HACMP resources its counterpart function, AddResources
#		added for INSTANCE_NAME.
# 		Entries added by AddResources in the HACMPsa_metadata ODM will also
#		be cleaned up.
#
# 		This function, for the most part, will print out a warning and
#		continue removing other resources should it fails removing a
#		particular resource.
#
# Syntax:
#       RemoveResources
#
# Arguments:  none
#
# Global Variables:
#   INSTANCE_NAME
#   NODE_LIST
#   DB2SA_SBIN_DIR
#
# Returns:
#   0 on SUCCESS
#   1 on FAILURE

function RemoveResources {
	[[ "$VERBOSE_LOGGING" == "high" ]] && set -x

	REMOVE_ERROR=0  # set to 1 if any of the remove fails

    sa_type="SA_DB2Instance"
    key="$APPLICATION_NAME"

    # Determine if the instance resource group exists first prior to removing
    typeset group=$(KLIB_AIX_ODM_get_odm_fields "sa_key=$key and sa_type=SA_DB2Instance" \
"HACMPgroup" "group")
    if [[ -z $group ]]; then
        errmsg 2 40
    fi

    typeset service_label=$(KLIB_AIX_ODM_get_odm_fields "name=SERVICE_LABEL and \
group=$group" "HACMPresource" "value")

    # Now, we remove all entries from HACMP.
    # Remove Application Server from the HACMP Configuration
    cllsserv -n $INSTANCE_NAME"_ApplicationServer" > /dev/null 2>&1
    if [[ $? -eq 0 ]]; then
        clrmserv $INSTANCE_NAME"_ApplicationServer"
        if [[ $? -ne 0 ]]; then
            errmsg 2 30 
            REMOVE_ERROR=1
        fi
    else
        errmsg 2 39 
    fi

    # Remove Service IP Label from the HACMP.
    clvt query service_ip $SERVICE_LABEL > /dev/null 2>&1
    if (( $? == 0 )); then
        clrmnode -a $SERVICE_LABEL
        if [[ $? -ne 0 ]]; then
            errmsg 2 57 
            REMOVE_ERROR=1
        fi
    else
        errmsg 2 58 
    fi

    # Remove Resource Group from the HACMP configuration
    # All of the metadata will be removed at the time the RG
	# metadata is removed
    if [[ -n $group ]]; then
	#
	# Removing the depedency, if any with
	# the RG we are going to remove.
	# We can't remove the RG, without removing
	# any dependency exists with the RG.
	#
	clvt delete dependency RG=$group 1>/dev/null 2>&1

        clrmgrp -g $group
        if (( $? != 0 )); then
            errmsg 2 31 
            REMOVE_ERROR=1
        fi
    fi

    # Remove the hard link for SQL Monitor for $INSTANCE_NAME
    for node in $NODE_LIST
    do
        cl_rsh $node "$DB2SA_SBIN_DIR/cl_db2link -r $INSTANCE_NAME" > /dev/null 2>&1
        if (( $? != 0 )); then
            errmsg 2 42 $INSTANCE_NAME $node
            REMOVE_ERROR=1
        fi
    done

    return $REMOVE_ERROR
}

#-----------------------------------------------------------------------------
#
# Name: StopInstance
#
# Checks the $NODE_LIST to make sure the instance is not running anywhere.  If
# found running, an attempt will be made to stop it.
#
# Arguments:  none
#
# Global Variables:
#	INSTANCE_NAME
#	NODE_LIST
#
# Returns:
#	0 on SUCCESS
#	1 on FAILURE
#
function StopInstance {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    export NODE2STOP=""

    # The product (*) of these will dictate how long we wait for the
	# instance to stop.  We wait up to $TOTAL_SLEEP_TIME seconds for the
	# instance to stop.
    typeset -i SLEEP_TIME=5	# in seconds
    typeset -i SLEEP_CYCLE=120
    typeset -i TOTAL_SLEEP_TIME
	(( TOTAL_SLEEP_TIME = $SLEEP_TIME * $SLEEP_CYCLE ))

    # Verify and stop the instance if running.
    for node in $NODE_LIST
    do
        cl_rsh $node "LC_ALL=C ps -fu$INSTANCE_NAME -o args | grep -v grep | grep -w db2sysc" > /dev/null 2>&1
        if (( $? == 0 )); then
            NODE2STOP="$node"
            cl_rsh $NODE2STOP "$DB2SA_SBIN_DIR/cl_db2stop $INSTANCE_NAME" > /dev/null 2>&1
			errmsg 2 43 $INSTANCE_NAME $NODE2STOP
        fi
    done

    if [[ -z $NODE2STOP ]]; then
        errmsg 2 48 $INSTANCE_NAME
        return 0
    fi

    # Check to see if the instance is stopped, if not, cycle through a sleep
    # to give it more time.
    while (( $SLEEP_CYCLE > 0 ))
    do
        cl_rsh $NODE2STOP "LC_ALL=C ps -fu$INSTANCE_NAME -o args | grep -v grep | grep -w db2sysc" > /dev/null 2>&1
        if (( $? == 0 )); then
            errmsg 2 44 $INSTANCE_NAME $NODE2STOP
            errmsg 2 45 $SLEEP_TIME $TOTAL_SLEEP_TIME

            sleep $SLEEP_TIME

            (( SLEEP_CYCLE = $SLEEP_CYCLE - 1 ))
        else
            errmsg 2 46 $INSTANCE_NAME $NODE2STOP
            return 0
        fi
    done

    errmsg 2 47 $INSTANCE_NAME $NODE2STOP
    return 1
}

#-----------------------------------------------------------------------------
#
# Name: CheckInputs
#
# Description:
#
# Checks a number of basic conditions and inputs to make sure nothing major is
# missing before adding any resources.  The checking here is by no mean
# exhaustive since this script is meant to be called from SMIT and that DB2
# Instance Discovery and Pre-Verification should have been executed prior to
# calling DB2 Import.
#
# Arguments:  none
#
# Global Variables:
#	INSTANCE_NAME
#	INSTANCE_OWNING_NODE
#	TAKEOVER_NODES
#	DATABASE_NAME
#	IP_NETWORK
#
# Returns:
#	0 on SUCCESS
#	1 on FAILURE
#
function CheckInputs {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    # Make sure the DB2 instance owner is a valid system user.
    errmsg 1 3 $INSTANCE_NAME
    lsuser -a home $INSTANCE_NAME > /dev/null 2>&1
    if [[ $? -ne 0 ]]; then
        errmsg 1 4 $INSTANCE_NAME
        exit 1
    fi

    # Make sure the DB2 instance exists in the Instance Discovery Database.
    errmsg 2 2
    xDB2INSTANCE=`KLIB_DB2_disc_get_instance_value $INSTANCE_NAME "DB2INSTANCE"` > /dev/null 2>&1
    if [[ -z $xDB2INSTANCE ]]; then
        errmsg 2 3 $INSTANCE_NAME
        errmsg 2 4 $INSTANCE_NAME
        exit 1
    fi

    # Make sure the DB2 instance database to be monitored exists in the Meta Database.
    errmsg 2 5
    xDATABASE_NAME=`LC_ALL=C KLIB_DB2_disc_get_instance_value $INSTANCE_NAME "DATABASES" | grep -i -w $DATABASE_NAME` > /dev/null 2>&1
    if [[ -z $xDATABASE_NAME ]]; then
        errmsg 2 6 $DATABASE_NAME
        exit 1
    fi

    # Make sure the owning node (-o) is not also part of the takeover node(s) (-n).
    errmsg 2 7
    NODE_LIST_OK=1		# assuming it's OK
    for i in $TAKEOVER_NODES
    do
        if [[ "$i" == "$INSTANCE_OWNING_NODE" ]]; then
            NODE_LIST_OK=0	# The instance owning node cannot also be part of the takeover nodes!
        fi
    done
    if (( $NODE_LIST_OK == "0" )); then
        errmsg 2 8 $INSTANCE_OWNING_NODE $TAKEOVER_NODES
        exit 1
    fi

    # Make sure all cluster nodes (-o & -n) are valid HACMP nodes.
    errmsg 2 9
    for node in $INSTANCE_OWNING_NODE $TAKEOVER_NODES
    do
        KLIB_HACMP_is_known_node $node
        if [[ $? -ne 0 ]]; then
            errmsg 2 10 $node
            errmsg 2 11
            exit 1
        fi
    done

    # Make sure $IP_NETWORK is using IPAT via IP Aliases (alias = 1 in HACMPnetwork).
    LC_ALL=C odmget -q "name = $IP_NETWORK" HACMPnetwork | grep -q 'alias = "1"'
    if (( $? != 0 )); then
        errmsg 2 32 $IP_NETWORK
        exit 1
    fi

    return 0
}


#-----------------------------------------------------------------------------
#
# Function:     GenerateRecoveryScript
#
# Description:  Run the recovery script and recover to PIT prior to removal
#
# Arguments:    instance - DB2 instance name
#
# Global Variables:
#               RECOVERY_CMDS
#               RECOVERY_ODM
#
# Returns:      0 if successful
#               !0 if a failure occurred
#
function GenerateRecoveryScript {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    typeset instance=$1
    typeset key="$APPLICATION_NAME"
    typeset group=$(KLIB_AIX_ODM_get_odm_fields "sa_key=$key and sa_type=SA_DB2Instance and group="$INSTANCE_NAME"_ResourceGroup" "HACMPgroup" "group")
    typeset service_label=$(KLIB_AIX_ODM_get_odm_fields "name=SERVICE_LABEL and group=$group" "HACMPresource" "value")
    typeset application_server=$(KLIB_HACMP_get_appserver $group)

    echo "/usr/bin/odmdelete -o HACMPgroup -q group=$group" > $RECOVERY_CMDS
    echo "/usr/bin/odmdelete -o HACMPresource -q group=$group" >> $RECOVERY_CMDS
    echo "/usr/bin/odmdelete -o HACMPsa_metadata -q application_id=$APPLICATION_NAME" >> $RECOVERY_CMDS
    echo "/usr/bin/odmdelete -o HACMPserver -q name=$application_server" >> $RECOVERY_CMDS
    echo "/usr/bin/odmdelete -o HACMPadapter -q ip_label=$service_label" >> $RECOVERY_CMDS
    MONITORS=$(LC_ALL=C clvt query application $application_server | \
                       grep ASSOCIATEDMONITORS | \
                       awk -F= '{print $2}' | sed -e "s/\"//g")
    for app_mon in $MONITORS
    do
        echo "/usr/bin/odmdelete -o HACMPmonitor -q monitor=$app_mon" >> $RECOVERY_CMDS
    done
    echo "/usr/bin/odmdelete -o HACMPrgdependency -q group_parent=$group" >> $RECOVERY_CMDS
    echo "/usr/bin/odmdelete -o HACMPrgdependency -q group_child=$group" >> $RECOVERY_CMDS
    echo "/usr/bin/odmdelete -o HACMPrg_loc_dependency -q group_name=$group" >> $RECOVERY_CMDS

    /usr/bin/odmget -q group=$group HACMPgroup > $RECOVERY_ODM
    /usr/bin/odmget -q group=$group HACMPresource >> $RECOVERY_ODM
    /usr/bin/odmget -q "application_id=$APPLICATION_NAME" HACMPsa_metadata >> $RECOVERY_ODM
    /usr/bin/odmget -q "name=$application_server" HACMPserver  >> $RECOVERY_ODM
    /usr/bin/odmget -q "ip_label=$service_label" HACMPadapter >> $RECOVERY_ODM
    for app_mon in $MONITORS
    do
        /usr/bin/odmget -q "monitor=$app_mon" HACMPmonitor >> $RECOVERY_ODM
    done
    /usr/bin/odmget -q group_parent=$group HACMPrgdependency >> $RECOVERY_ODM
    /usr/bin/odmget -q group_child=$group HACMPrgdependency >> $RECOVERY_ODM
    /usr/bin/odmget -q group_name=$group HACMPrg_loc_dependency >> $RECOVERY_ODM

    #
    # Providing execute permissions
    #
    /usr/bin/chmod u+x $RECOVERY_CMDS
    /usr/bin/chmod u+x $RECOVERY_ODM
}

#-----------------------------------------------------------------------------
#
# Function:     RunRecoveryScript
#
# Description:  Run the recovery script and recover to PIT prior to removal
#
# Arguments:    na
#
# Global Variables:
#               RECOVERY_CMDS
#               RECOVERY_ODM
#
# Returns:      0 if successful
#               !0 if a failure occurred
#
function RunRecoveryScript {
    set +u
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    set -u

    /usr/bin/ksh93 $RECOVERY_CMDS 2>/dev/null
    /usr/bin/odmadd $RECOVERY_ODM 2>/dev/null
}

#-----------------------------------------------------------------------------
#
# Function:     RemoveRecoveryScript
#
# Description:  Remove the recovery script files from /tmp/
#               prior to exiting
#
# Arguments:    na
#
# Global Variables:
#               RECOVERY_CMDS
#               RECOVERY_ODM
#
# Returns:      0 if successful
#               !0 if a failure occurred
#
function RemoveRecoveryScript {
    set +u
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x
    set -u

    rm -f $RECOVERY_ODM $RECOVERY_CMDS
}

#################################################################################
#
# Function: Add_DB_CE_PE_resources
#
# Description:  Updates DB for Content Engine resources in DB for Process Engine
#		RG and vice versa.
#
# Syntax:
#       Add_DB_CE_PE_resources <list of VGs need to be udpated>
#
# Arguments: none
#
# Global Variables:
#	INSTANCE_NAME
#	DATABASE_NAME
#	APPLICATION_NAME
#
# Returns:
#       0 on SUCCESS
#       1 on FAILURE
#
#################################################################################

function Add_DB_CE_PE_resources {
	[[ "$VERBOSE_LOGGING" == "high" ]] && set -x

	typeset -n SHARED_VGS=$1

	for DB in $DATABASE_NAME
        do
                claddappmon MONITOR_TYPE=user name="${INSTANCE_NAME}_${DB}_SQLMonitor" \
                        RESOURCE_TO_MONITOR="${INSTANCE_NAME}_ApplicationServer" \
                        INVOCATION='longrunning' \
                        MONITOR_METHOD="$DB2SA_SBIN_DIR/cl_db2cmon -i $INSTANCE_NAME -A $APPLICATION_NAME -d $DB" \
                        MONITOR_INTERVAL='120' \
                        HUNG_MONITOR_SIGNAL='9' \
                        STABILIZATION_INTERVAL='240' \
                        RESTART_COUNT='3' \
                        RESTART_INTERVAL='1440' \
                        FAILURE_ACTION='fallover' \
                        CLEANUP_METHOD="$DB2SA_SBIN_DIR/cl_db2stop $INSTANCE_NAME" \
                        RESTART_METHOD="$DB2SA_SBIN_DIR/cl_db2start $INSTANCE_NAME"

                if (( $? != 0 )); then
                        errmsg 2 19 $INSTANCE_NAME
                        return 1
                fi
        done

	set -a
	eval $(clvt query resource_group "$INSTANCE_NAME"_ResourceGroup)
	set +a

	#
	# Find out the unique VG list
	#
	VG_LIST=$VOLUME_GROUP
	SHARED_VGS=${SHARED_VGS// /}
	for VG in $SHARED_VGS; do
		available=0
		for VG_IN_RG in $VOLUME_GROUP; do
			[[ $VG == $VG_IN_RG ]] && {
				available=1
				break
			}
		done
		(( $available -eq 0 )) && {
			VG_LIST="$VG_LIST $VG"
		}
	done

	# Add the resources to the resource group
	clvt modify resource_group "${INSTANCE_NAME}_ResourceGroup" \
               VOLUME_GROUP="$VG_LIST" APPLICATIONS="$APPLICATIONS" \
               SERVICE_LABEL="$SERVICE_LABEL" FORCED_VARYON='false' \
               VG_AUTO_IMPORT='true' FSCHECK_TOOL='fsck' \
               RECOVERY_METHOD='parallel' FS_BEFORE_IPADDR='false'

	if (( $? != 0 )); then
		errmsg 2 24 $INSTANCE_NAME
		return 1
	fi

	for DB in $DATABASE_NAME
        do
                claddsaapp -a "$APPLICATION_NAME" \
                        SQL_MONITOR="${INSTANCE_NAME}_${DB}_SQLMonitor" || {
                        errmsg 2 20
                        return 1
                }
        done

	#
	# cl_db2cmon needs this to figure out which DB to monitor.
	# Find out the existing DBs to monitor from HACMPsa_metadata ODM
	#
	DBS_MONITOR=""
	DBS_MONITOR=$(clodmget -q "application_id=$APPLICATION_NAME and \
name=DATABASE_TO_MONITOR" -f value -d "=" HACMPsa_metadata)
	if [[ -n $DBS_MONITOR ]]; then
		DBS_MONITOR=${DBS_MONITOR//\"/}
		DBS_MONITOR="$DBS_MONITOR $DATABASE_NAME"
	else
		DBS_MONITOR="$DATABASE_NAME"
	fi

        claddsaapp -a "$APPLICATION_NAME" \
                DATABASE_TO_MONITOR="$DBS_MONITOR" || {
		errmsg 2 50
		return 1
        }

	name=$(KLIB_AIX_ODM_get_odm_fields "value=${INSTANCE_NAME}_ResourceGroup and application_id=$APPLICATION_NAME" "HACMPsa_metadata" "name")
	clrmsaapp -a $APPLICATION_NAME $name

	RG="FILENET_DB_PE_CE_RESOURCE_GROUP"
	claddsaapp -a $APPLICATION_NAME \
                $RG="${INSTANCE_NAME}_ResourceGroup" || {
		errmsg 2 25
		return 1
        }

	return 0
}


#-----------------------------------------------------------------------------
#
# Name: AddResources
#
# Description:
#		Adds (-a) HACMP resources for DB2 Smart Assist.  If the resources
#		already exist, they will be removed and then added.  Entries will
#		also be added to the HACMPsa_metadata ODM.  Application Discovery
#		will remove the resources constructed by this function
#
# Syntax:
#       AddResources
# 
# Arguments: none
# 
# Global Variables:
#	INSTANCE_NAME
#	INSTANCE_OWNING_NODE
#	TAKEOVER_NODES
#	SERVICE_LABEL
#	IP_NETWORK
#	NODE_LIST
#	DB2SA_SBIN_DIR
#
# Returns:
#	0 on SUCCESS
#	1 on FAILURE
#
function AddResources {
    [[ "$VERBOSE_LOGGING" == "high" ]] && set -x

    DB2HOME_VG=$(KLIB_DB2_disc_get_instance_value $INSTANCE_NAME "DB2HOME_VG")
    OTHERVGS=$(KLIB_DB2_disc_get_instance_value $INSTANCE_NAME "OTHERVGS")
    SHARED_VGS="$DB2HOME_VG $OTHERVGS"          # all the shared VG(s) for the instance
    typeset source_node=$(KLIB_DB2_disc_get_instance_value $INSTANCE_NAME "CLUSTER_NODE")
	typeset application
	typeset DB_MON
	typeset DB_CE_RG
	typeset DB_PE_RG
	typeset DB_PE_CE_RG

    for node in $TAKEOVER_NODES; do
        KLIB_DB2_VG_node_pvid_compare $source_node $node $DB2HOME_VG || {
                SHARED_VGS="$OTHERVGS"
                break
        }
    done

	[[ "$COMPONENT_ID" == "FILENET_DB_PROCESS_ENGINE" ]] && {
		application=$(KLIB_AIX_ODM_get_odm_fields "name=INSTANCE_NAME and value=$INSTANCE_NAME" "HACMPsa_metadata" "application_id")
		[[ -n "$application" ]] && {
			DB_CE_RG=$(KLIB_AIX_ODM_get_odm_fields "name=FILENET_DB_CE_RESOURCE_GROUP and application_id=$application" "HACMPsa_metadata" "value")
			DB_PE_CE_RG=$(KLIB_AIX_ODM_get_odm_fields "name=FILENET_DB_PE_CE_RESOURCE_GROUP and application_id=$application" "HACMPsa_metadata" "value")
			[[ -n $DB_CE_RG && -z $DB_PE_CE_RG ]] && {
				DB_CE_RG=${DB_CE_RG//\"/}
				KLIB_SA_logmsg INFO 11 3 filenetsa.cat "The Database for Process and Content Engine, both are deployed\n\
under same DB2 instance %1\$s, so adding required resources\n\
of Database for %2\$s Engine onto Database for\n\
%3\$s Engine Resource Group %4\$s" $INSTANCE_NAME Process Content $DB_CE_RG
				RC=$(Add_DB_CE_PE_resources SHARED_VGS)
				return $RC
			}
		}
	}

	[[ "$COMPONENT_ID" == "FILENET_DB_CONTENT_ENGINE" ]] && {
                application=$(KLIB_AIX_ODM_get_odm_fields "name=INSTANCE_NAME and value=$INSTANCE_NAME" "HACMPsa_metadata" "application_id")
                [[ -n "$application" ]] && {
                        DB_PE_RG=$(KLIB_AIX_ODM_get_odm_fields "name=FILENET_DB_PE_RESOURCE_GROUP and application_id=$application" "HACMPsa_metadata" "value")
                        DB_PE_CE_RG=$(KLIB_AIX_ODM_get_odm_fields "name=FILENET_DB_PE_CE_RESOURCE_GROUP and application_id=$application" "HACMPsa_metadata" "value")
                        [[ -n $DB_PE_RG && -z $DB_PE_CE_RG ]] && {
				DB_PE_RG=${DB_PE_RG//\"/}
				KLIB_SA_logmsg INFO 11 3 filenetsa.cat "The Database for Process and Content Engine, both are deployed\n\
under same DB2 instance %1\$s, so adding required resources\n\
of Database for %2\$s Engine onto Database for\n\
%3\$s Engine Resource Group %4\$s" $INSTANCE_NAME Content Process $DB_PE_RG
				RC=$(Add_DB_CE_PE_resources SHARED_VGS)
				return $RC
                        }

                }
        }


    #
    # Check, is there any application configured with the
    # input application name
    #
    clquerysaapp -a $APPLICATION_NAME 1>/dev/null 2>&1
    (( $? == 0 )) && {
        KLIB_SA_logmsg ERROR 9999 9999 filenetsa.cat "There exist some configuration \
with application name %1\$s\n\
Please choose a different application name" $APPLICATION_NAME
        return 1
    }

    # First remove any pre-existing resources for this application id
      RemoveResources

    (( $? != 0 )) && {
	return 1
    }

    # Add an entry into the HACMPsa_metadata ODM for the application id
    # and SMARTASSIST_ID and COMPONENT_ID
    claddsaapp -a "$APPLICATION_NAME" SMARTASSIST_ID='FILENET' \
COMPONENT_ID="$COMPONENT_ID" APPLICATION_NAME="$APPLICATION_NAME" INSTANCE_NAME="$INSTANCE_NAME"

    # Add the DB2 instance metadata to HACMPsa_metadata via the application
    # discovery framework (claddsaapp)
    KLIB_DB2_add_instance_to_metadata $INSTANCE_NAME APPLICATION_NAME

    sa_type="SA_DB2Instance"
    key="$INSTANCE_NAME"

    # Create the Service IP Label
    claddnode -Tservice -B"$SERVICE_LABEL" -w"$IP_NETWORK"
    if [[ $? -ne 0 ]]; then
        errmsg 2 53 $INSTANCE_NAME
        return 1
    fi

	# Remove the application server first, in case it already exists
	clrmserv $INSTANCE_NAME"_ApplicationServer" >/dev/null 2>&1

    # Create the Instance Application Server
    claddserv -s $INSTANCE_NAME"_ApplicationServer" \
    		  -b "$DB2SA_SBIN_DIR/cl_db2start ${INSTANCE_NAME}" \
              -e "$DB2SA_SBIN_DIR/cl_db2stop ${INSTANCE_NAME}"
    if [[ $? -ne 0 ]]; then
        errmsg 2 17 $INSTANCE_NAME
        return 1
    fi

	# Create the Instance SQL Monitor
	for DB in $DATABASE_NAME
	do
		claddappmon MONITOR_TYPE=user name="${INSTANCE_NAME}_${DB}_SQLMonitor" \
                RESOURCE_TO_MONITOR="${INSTANCE_NAME}_ApplicationServer" \
                INVOCATION='longrunning' \
                MONITOR_METHOD="$DB2SA_SBIN_DIR/cl_db2cmon -i $INSTANCE_NAME -A $APPLICATION_NAME -d $DB" \
                MONITOR_INTERVAL='120' \
                HUNG_MONITOR_SIGNAL='9' \
                STABILIZATION_INTERVAL='240' \
                RESTART_COUNT='3' \
                RESTART_INTERVAL='1440' \
                FAILURE_ACTION='fallover' \
                CLEANUP_METHOD="$DB2SA_SBIN_DIR/cl_db2stop $INSTANCE_NAME" \
                RESTART_METHOD="$DB2SA_SBIN_DIR/cl_db2start $INSTANCE_NAME"

		if (( $? != 0 )); then
			errmsg 2 19 $INSTANCE_NAME
			return 1
		fi

		claddsaapp -a "$APPLICATION_NAME" \
                        SQL_MONITOR="${INSTANCE_NAME}_${DB}_SQLMonitor" \
                        $name="$value" || {
			errmsg 2 20
			return 1
		}
	done

	#
        # Find out the existing DBs to monitor from HACMPsa_metadata ODM
        #
	DBS_MONITOR=""
        DBS_MONITOR=$(clodmget -q "application_id=$APPLICATION_NAME and \
name=DATABASE_TO_MONITOR" -f value -d "=" HACMPsa_metadata)
        if [[ -n $DBS_MONITOR ]]; then
                DBS_MONITOR=${DBS_MONITOR//\"/}
                DBS_MONITOR="$DBS_MONITOR $DATABASE_NAME"
	else
		DBS_MONITOR="$DATABASE_NAME"
	fi

	# cl_db2cmon needs this to figure out which DB to monitor
	claddsaapp -a "$APPLICATION_NAME" \
		DATABASE_TO_MONITOR="$DBS_MONITOR" || {
            errmsg 2 50
            return 1
	}

    # Create the Instance Process Monitor
    claddappmon MONITOR_TYPE=process name="${INSTANCE_NAME}_ProcessMonitor" \
    		RESOURCE_TO_MONITOR="${INSTANCE_NAME}_ApplicationServer" \
		INVOCATION='longrunning' \
    		PROCESSES='db2sysc' \
		PROCESS_OWNER="$INSTANCE_NAME" \
		INSTANCE_COUNT='1' \
		STABILIZATION_INTERVAL='240' \
    		RESTART_COUNT='3' \
		RESTART_INTERVAL='1440' \
		FAILURE_ACTION='fallover' \
    		CLEANUP_METHOD="$DB2SA_SBIN_DIR/cl_db2stop $INSTANCE_NAME" \
    		RESTART_METHOD="$DB2SA_SBIN_DIR/cl_db2start $INSTANCE_NAME"
    if (( $? != 0 )); then
        errmsg 2 21 $INSTANCE_NAME
        return 1
	fi

	claddsaapp -a $APPLICATION_NAME \
		PROCESS_MONITOR="${INSTANCE_NAME}_ProcessMonitor" || {
    	errmsg 2 22
        return 1
	}

	
	[[ -z "$RG" ]] && {
		[[ "$COMPONENT_ID" == "FILENET_DB_PROCESS_ENGINE" ]] && {
			RG="FILENET_DB_PE_RESOURCE_GROUP"
		}

		[[ "$COMPONENT_ID" == "FILENET_DB_CONTENT_ENGINE" ]] && {
			RG="FILENET_DB_CE_RESOURCE_GROUP"
		}
	}


	claddsaapp -a $APPLICATION_NAME \
		$RG="${INSTANCE_NAME}_ResourceGroup" || {
    	errmsg 2 25
    	return 1
	}

    # Create the Instance Resource Group
    claddgrp -g "${INSTANCE_NAME}_ResourceGroup" \
		-n "$NODE_LIST" \
		-S 'OHN' -O 'FNPN' -B 'NFB' \
		-A SA_DB2Instance -K ${APPLICATION_NAME}
    if (( $? != 0 )); then
        errmsg 2 23 $INSTANCE_NAME
        return 1
    fi

	# Add the resources to the resource group
    claddres -g "${INSTANCE_NAME}_ResourceGroup" \
		SERVICE_LABEL="$SERVICE_LABEL" \
    		APPLICATIONS="${INSTANCE_NAME}_ApplicationServer" \
		VOLUME_GROUP="$SHARED_VGS" \
		FORCED_VARYON='false' \
    		VG_AUTO_IMPORT='true' \
		FILESYSTEM="" \
		FSCHECK_TOOL='fsck' \
		RECOVERY_METHOD='parallel' \
		FS_BEFORE_IPADDR='false' \
    		EXPORT_FILESYSTEM= \
		MOUNT_FILESYSTEM= \
		NFS_NETWORK="" \
		SHARED_TAPE_RESOURCES= \
		DISK="" \
		AIX_FAST_CONNECT_SERVICES= \
    		COMMUNICATION_LINKS= \
		MISC_DATA=""
    if (( $? != 0 )); then
        errmsg 2 24 $INSTANCE_NAME
        return 1
    fi

#
# Creating Dependencies
# 1. Process Engine RG should start after DB for Process Engine RG
# 2. Content Engine RG should start after DB for Content Engine RG
#
CE_RG=$(clodmget -q "name=CONTENT_ENGINE_RESOURCE_GROUP" -f value -d "=" HACMPsa_metadata)
CE_RG=${CE_RG//\"/}
AE_CE_RG=$(clodmget -q "name=FILENET_AE_CE_RESOURCE_GROUP" -f value -d "=" HACMPsa_metadata)
AE_CE_RG=${AE_CE_RG//\"/}
PE_RG=$(clodmget -q "name=PROCESS_ENGINE_RESOURCE_GROUP" -f value -d "=" HACMPsa_metadata)
PE_RG=${PE_RG//\"/}
AE_RG=$(clodmget -q "name=APPLICATION_ENGINE_RESOURCE_GROUP" -f value -d "=" HACMPsa_metadata)
AE_RG=${AE_RG//\"/}

[[ "$RG" == "FILENET_DB_PE_RESOURCE_GROUP" ]] && {
	[[ -n "$PE_RG" ]] && {
		clrgdependency -t 'START_AFTER' -a -c "$PE_RG" -p "${INSTANCE_NAME}_ResourceGroup"
		(( $? != 0 )) &&
			return 1
	}
	#
	# Establishing NODECOLLOCATION dependency across process engine RG and
	# DB for Process engine RG
	#
	clrgdependency -t 'NODECOLLOCATION' -a -l "${INSTANCE_NAME}_ResourceGroup $PE_RG"
	(( $? != 0 )) &&
		return 1
}

[[ "$RG" == "FILENET_DB_CE_RESOURCE_GROUP" ]] || [[ "$RG" == "FILENET_DB_PE_CE_RESOURCE_GROUP" ]] && {
	[[ -n "$AE_RG" && -n "$CE_RG" && -n "$PE_RG" ]] && {
		clrgdependency -t 'START_AFTER' -d -c "$PE_RG" -p "$CE_RG"
		(( $? != 0 )) &&
                        return 1
	}
}

[[ "$RG" == "FILENET_DB_CE_RESOURCE_GROUP" ]] && {
	[[ -n "$CE_RG" ]] && {
		clrgdependency -t 'START_AFTER' -a -c "$CE_RG" -p "${INSTANCE_NAME}_ResourceGroup"
		(( $? != 0 )) &&
                        return 1
	}
	[[ -n "$AE_CE_RG" ]] && {
		clrgdependency -t 'START_AFTER' -a -c "$AE_CE_RG" -p "${INSTANCE_NAME}_ResourceGroup"
		(( $? != 0 )) &&
                        return 1
	}
}

[[ "$RG" == "FILENET_DB_PE_CE_RESOURCE_GROUP" ]] && {
	[[ -n "$CE_RG" ]] && {
		clrgdependency -t 'START_AFTER' -a -c "$CE_RG" -p "${INSTANCE_NAME}_ResourceGroup"
		(( $? != 0 )) &&
                        return 1
	}

	[[ -n "$AE_CE_RG" ]] && {
                clrgdependency -t 'START_AFTER' -a -c "$AE_CE_RG" -p "${INSTANCE_NAME}_ResourceGroup"
		(( $? != 0 )) &&
                        return 1
        }

	[[ -n "$PE_RG" ]] && {
		clrgdependency -t 'START_AFTER' -a -c "$PE_RG" -p "${INSTANCE_NAME}_ResourceGroup"
		(( $? != 0 )) &&
                        return 1
		#
                # Establishing NODECOLLOCATION dependency across process engine RG and
                # DB for Process engine RG
                #
                clrgdependency -t 'NODECOLLOCATION' -a -l "${INSTANCE_NAME}_ResourceGroup $PE_RG"
		(( $? != 0 )) &&
                        return 1
	}
}
    return 0
}


#-----------------------------------------------------------------------------
# Main:
#-----------------------------------------------------------------------------

umask -S u=rw,g=,o=

[[ $NUM_ARGS -eq 0 ]] && usage

while getopts DA:C:Mvaro:n:i:d:l:w: option
do
    case $option in
        D) # Verbose on + Debug on
            VERBOSE=1
            DEBUG=1 ;;
	A) # application name
	    APPLICATION_NAME=$OPTARG ;;
	C) # Component Identifier either DB2_NON_DPF_SINGLE or
	   # DB2_NON_DPF_MUTUAL
	    COMPONENT_ID=$OPTARG ;;
        v) # Verbose on
            VERBOSE=1 ;;
        a) # Add Resources
            if [[ "$REMOVE_RESOURCES" == "1" ]]; then
               usage
            fi
            ACTION="add"
            ADD_RESOURCES=1 ;;
	    r) # Remove Resources
            if [[ "$ADD_RESOURCES" == "1" ]]; then
               usage
            fi
            ACTION="remove"
            REMOVE_RESOURCES=1 ;;
        o) # Primary cluster node that owns the instance
            INSTANCE_OWNING_NODE=$OPTARG ;;
        n) # Standby cluster node(s) that is/are capable of hosting the instance
            TAKEOVER_NODES="$OPTARG"
            TAKEOVER_NODES=$(echo $TAKEOVER_NODES | sed -e "s/\:/ /g") ;;
        i) # Name of instance to be made highly available
            INSTANCE_NAME=$OPTARG ;;
        d) # Name of instance database to be used by the custom SQL monitor
            DATABASE_NAME=$OPTARG ;;
        l) # Service IP label for instance
            SERVICE_LABEL=$OPTARG ;;
        w) # IP network where Service IP label lives
            IP_NETWORK=$OPTARG ;;
	M) # Delete the pre-existing configuration (modify mode)
	    MODIFY_MODE=true ;;
        *)
            usage
    esac
done

export NODE_LIST="$INSTANCE_OWNING_NODE $TAKEOVER_NODES"

if (( $ADD_RESOURCES == 0 )) && (( $REMOVE_RESOURCES == 0 )); then
    errmsg 2 49 
    usage
fi

errmsg 1 6 
if [[ -f $DB2SA_DISC_FILE ]]; then
    . $DB2SA_DISC_FILE
else
    if [[ "$ACTION" == "add" ]]; then
    	errmsg 1 5 
   	exit 1
    fi
fi

# Verify and, if needed, stop the instance before moving on.
StopInstance
if (( $? != 0 )); then
    errmsg 2 42 $INSTANCE_NAME $INSTANCE_OWNING_NODE
    exit 1
fi

if [[ "$ACTION" == "add" ]]; then
    clsapre
    CheckInputs
    if [[ $? -ne 0 ]]; then
        errmsg 2 33 
        exit 1
    fi

    #
    # Remove the pre-existing configuration (modify mode)
    #
    [[ "$MODIFY_MODE" == "true" ]] && {
        GenerateRecoveryScript $INSTANCE_NAME
        set -a
        eval $(clquerysaapp -a $APPLICATION_NAME RESOURCE_GROUP)
        set +a
        service_ip_label=$(clodmget -q "name=SERVICE_LABEL and \
group=$RESOURCE_GROUP" -f value -d "=" HACMPresource)
        service_ip_label=${service_ip_label//\"/}
        [[ -n $service_ip_label ]] &&
                clvt delete service_ip $service_ip_label

        #
        # Removing the depedency, if any with
        # the RG we are going to remove.
        # We can't remove the RG, without removing
        # any dependency exists with the RG.
        #
        clvt delete dependency RG=$RESOURCE_GROUP 1>/dev/null 2>&1

        clvt delete resource_group $RESOURCE_GROUP

        RG=$(clodmget -q "value=$RESOURCE_GROUP" -f name -d "=" HACMPsa_metadata)
        RG=${RG//\"/}

        clrmsaapp -a $APPLICATION_NAME
    }
    #
    # Determine if the instance we're attempting to add is already part of an
    # HACMP configuration (configured using DB2 smart assist)
    #
    # Check to ensure another resource group with the same application name hasn't been
    # created (using DB2 smart assist)
    #
    application=$(KLIB_AIX_ODM_get_odm_fields "name=RESOURCE_GROUP and value=${INSTANCE_NAME}_ResourceGroup" "HACMPsa_metadata" "application_id")

    [[ -n $application ]] && {
	errmsg 2 59 $INSTANCE_NAME $application
	exit 1
    }
    AddResources
    if [[ $? -ne 0 ]]; then
	RemoveResources
        clquerysaapp -a $APPLICATION_NAME > /dev/null 2>&1
        (( $? == 0 )) && {
                clrmsaapp -a $APPLICATION_NAME
        }

	#
        # When something went wrong while adding resources
        # during change of application, we are restoring
        # back the original configuration.
        #
        [[ "$MODIFY_MODE" == "true" ]] && {
                RunRecoveryScript
		RemoveRecoveryScript
        }
        errmsg 2 12
        exit 1
    fi

    [[ "$MODIFY_MODE" == "true" ]] &&
	RemoveRecoveryScript

    clsapost -v
    (( $? != 0 )) && exit 1

else
    errmsg 2 14 
    exit 1
fi

exit 0
