#!/bin/bash -x

set -e

#The postinst script may be called in the following ways:

#'postinst configure most-recently-configured-version'
#		The files contained in the package will be unpacked. All package 
#		dependencies will at least be unpacked. If there are no circular 
#		dependencies involved, all package dependencies will be configured. 
#		For behavior in the case of circular dependencies, see the discussion 
#		in Binary Dependencies - Depends, Recommends, Suggests, Enhances, Pre-Depends, Section 7.2.

#old-'postinst abort-upgrade new-version'

#conflictor's-'postinst abort-remove in-favour package new-version'

#'postinst abort-remove'

#deconfigured's-'postinst abort-deconfigure in-favour failed-install-package version [removing conflicting-package version]'

#		The files contained in the package will be unpacked. All package 
#		dependencies will at least be "Half-Installed" and will have previously 
#		been configured and not removed. However, dependencies may not be 
#		configured or even fully unpacked in some error situations.[47] 
#		The postinst should still attempt any actions for which its dependencies 
#		are required, since they will normally be available, but consider 
#		the correct error handling approach if those actions fail. 
#		Aborting the postinst action if commands or facilities from the 
#		package dependencies are not available is often the best approach.

#####
##### Read the commandline options
##### Only 'configure' is handled with processing, other actions
##### are ignored for now
#####
ACTION=${1}
ARG_VERSION=${2}

#####
##### Source the debconf library
#####

if [ -e "/usr/share/debconf/confmodule" ]; then
    . /usr/share/debconf/confmodule
else
    echo "debconf must be installed. Exiting."
    exit 1
fi

#####
##### GLOBAL VARIABLES
#####

declare RECONFIGURE
declare FIRSTINST
declare UPGRADE
declare IP_ADDRESS
declare CONTEXT

# XML_TEMPLATE_FLAGS  associative array will contain the boolean values for the various flags as specified in the xml config file
# Data Structure=([templateName]="seen-flag derived-value-flag user-entered-value-flag configured-value-flag")
declare -A XML_TEMPLATE_FLAGS 

# XML_QUESTION_VALUES associative array will contain the value to the template questions as specified in the xml config file
# Data Structure=([templateName]="value")
declare -A XML_QUESTION_VALUES

# DEB_QUESTION_FLAGS associative array will contain the boolean values for the various flags as stored in the debian backend db
# Data Structure=([templateName]="seen-flag derived-value-flag user-entered-value-flag configured-value-flag")
declare -A DEB_QUESTION_FLAGS

# DEB_QUESTION_VALUES associative array will contain the values for the template questions as stored in the debian backend db
# Data Structure=([templateName]="value")
declare -A DEB_QUESTION_VALUES

# DEB_QUESTION_VALUES associative array will contain a boolean for the template questions that have changed in the debian backend db
# Data Structure=([templateName]="true|false")
declare -A DB_QUESTION_CHANGED
# The Global Constants

TOMCAT=tomcat9
TOMCAT_USER=tomcat
DATAONE_USER=tomcat
TOMCAT_HOME=/var/lib/tomcat9
JDK_PACKAGE=openjdk-8-jdk
JDK_HOME=/usr/lib/jvm/java-8-openjdk-amd64
DEFAULT_JAVA_HOME=/usr/lib/jvm/default-java
SOURCE_DIR=/usr/share/dataone-cn-os-core
SCRIPT_DIR=${SOURCE_DIR}/debian
APACHE_CONF_DIR=/etc/apache2
MOD_JK_CONF_DIR=/etc/libapache2-mod-jk
APACHE_WWW_DIR=/var/www
D1_CONF_DIR=/etc/dataone
NODE_PROPS="$D1_CONF_DIR/node.properties"
LDAP_CONF_DIR=/etc/ldap
SITES="cn-ssl"
JAVA_SECURITY=${JDK_HOME}/jre/lib/security/java.security
JAVA_SECURITY_EXT_DIR=${JDK_HOME}/jre/lib/ext
JAVA_KEYSTORE=${JDK_HOME}/jre/lib/security/cacerts
LDAP_USER=openldap
CILOGON_CERTS="cilogon-basic.pem cilogon-silver.pem cilogon-openid.pem"
SSL_CERT_DIR=/etc/ssl/certs
#SSL_SERVER_KEY_DIR=/etc/ssl/private/
D1_LOG_DIR=/var/log/dataone
D1_LOG_FILE=dataone-cn-os-core.install.log
D1_TMP_DIR=/tmp
D1_DEB_CONF_XML_URL="https://raw.githubusercontent.com/DataONEorg/dataone-cn-os-core/develop_2.3/etc/dataone/d1DebConfig.xml"
D1_DEB_CONF_XML="d1DebConfig.xml"
D1_DEB_XSD_URL="https://raw.githubusercontent.com/DataONEorg/d1_schemas/main/dataoneDebPkgConfigTypes.xsd"
D1_DEB_XSD="dataoneDebPkgConfigTypes.xsd"
SUCCESS=0
SERVER_SSL_PREFIX_DIR=/etc/letsencrypt/live
LOG4J='-Dlog4j2.formatMsgNoLookups=true'

#positions of the flags in XML_TEMPLATE_FLAGS and DEB_QUESTION_FLAGS
SEEN=0
DERIVED_VALUE=1
USER_ENTERED_VALUE=2
CONFIGURED_VALUE=3

# Use as suffix to backedup files
LONG_DATE=$(date +%Y%m%d%H%M%S)

# Create a difficult to guess token to pass for Solr auth
SOLR_TOKEN=`date +%m%s%Y%N%d | sed 's/0//g'`

#####
##### FUNCTION DEFINITIONS
#####

#####
##### logError()
##### redirect stdout to stderr
##### functions to echo to STDERR or the install log instead of STDOUT
#####
function logError() 
{
    echo -e "$@" 1>&2
}

#####
##### log()
##### append stdout to a logfile
#####
function log() 
{
	#
	# Set Up logging
	# Reminder: don't echo to stdout, it messes up debconf
	#
    if [ ! -e ${D1_LOG_DIR} ]; then
        mkdir -p ${D1_LOG_DIR}
    fi
    chown -R ${TOMCAT_USER}:${TOMCAT_USER} ${D1_LOG_DIR}
    now=$(date "+%Y-%m-%d %H:%M:%S %Z: ")
    echo -e "${now} postinst $@" >> ${D1_LOG_DIR}/${D1_LOG_FILE}
}
#####
##### exitWithFailureCode( ERROR_CODE )
##### Ensures that passwords are wiped, database is stopped and exit is called with an error code
##### 

function exitWithFailureCode()
{
		local errorCode=$1
		db_set dataone-cn-os-core/cn.openldap.password "" # clear the cached pw
		db_fset dataone-cn-os-core/cn.openldap.password seen false
		db_set dataone-cn-os-core/cn.keystore.password "" # clear the cached pw
		db_fset dataone-cn-os-core/cn.keystore.password seen false
		db_stop
		exit $errorCode
}

#####
##### join (EXPR, LIST)
##### Joins the separate strings of LIST into a single string with fields separated by the value of EXPR, and assigns that
##### new string to the global variable RTN_JOIN.
#####

RTN_JOIN="";
function join() {
        RTN_JOIN="";
        local exprString=$1
        shift
        local -a listFields=($@)
        tmpJoin=$(printf "${exprString}%s" "${listFields[@]}")
        RTN_JOIN=${tmpJoin:1}
        RTN_JOIN="${RTN_JOIN#"${RTN_JOIN%%[![:space:]]*}"}" # remove leading whitespace characters
        RTN_JOIN="${RTN_JOIN%"${RTN_JOIN##*[![:space:]]}"}" # remove trailing whitespace characters
        return
}


##### find out if ldap is running
##### if it is not try to restart
##### if it does not restart, then fail

function confirm_ldap_running() 
{
	if ! (pidof slapd  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		if ! (/etc/init.d/slapd start >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 );  then
			log "Slapd failed to start"
			return 1
		fi
		sleep 10
		if ! (pidof slapd  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Slapd cannot run"
			return 1
		fi
	fi

	return 0
}


#####
##### process_derived_debian_config()
##### Find all the templates in XML_QUESTION_VALUES that are marked as
##### derived from other elements in the xml file and fill them out
##### 

function process_derived_debian_config()
{
	log "start process_derived_debian_config"
	for template_name in ${!XML_QUESTION_VALUES[@]}
	do
		eval declare -a DEB_FLAG_BOOLEAN=("${DEB_QUESTION_FLAGS[$template_name]}")
		if [ "${DEB_FLAG_BOOLEAN[$SEEN]}" == "false" ]; then
			eval declare -a XML_TEMPLATE_BOOLEAN=("${XML_TEMPLATE_FLAGS[$template_name]}")
			
			if [ "${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}" == "true" ]; then
				local SEEN_FLAG="true"
				local CHANGED_FLAG="false"
				case "${template_name}" in
					"dataone-cn-os-core/cn.iplist")
						CN_IPLIST=(`xmlstarlet sel -t --match "//environment[@context='${CONTEXT}']/machine"  --value-of "concat(@ip, ' ')"  "$D1_CONF_DIR/${D1_DEB_CONF_XML}"`)
						join ' ' ${CN_IPLIST[@]}
						local IPLIST=${RTN_JOIN}
						
						db_get $template_name
						local DEB_IPLIST=$RET
						
						if [[ -n $DEB_IPLIST && $IPLIST != $DEB_IPLIST ]]; then
							CHANGED_FLAG="true"
						fi
						db_set $template_name ${IPLIST}
						# log "IPLIST ${IPLIST[@]}"
						DEB_QUESTION_VALUES+=([$template_name]="${IPLIST}")
						;;
					"dataone-cn-os-core/cn.hostnamelist")
						CN_HOSTNAMELIST=(`xmlstarlet sel -t --match "//environment[@context='${CONTEXT}']/machine/question[@keyref='dataone-cn-os-core/cn.hostname']"  --value-of "concat(text(), ' ')"  "$D1_CONF_DIR/${D1_DEB_CONF_XML}"`)
						join ' ' ${CN_HOSTNAMELIST[@]}
						local HOSTNAMELIST=${RTN_JOIN}
						
						db_get $template_name
						local DEB_HOSTNAMELIST=$RET
						
						if [[ -n $DEB_HOSTNAMELIST && $HOSTNAMELIST != $DEB_HOSTNAMELIST ]]; then
							CHANGED_FLAG="true"
						fi
						db_set $template_name ${HOSTNAMELIST}
						# log "HOSTNAMELIST ${HOSTNAMELIST[@]}"
						DEB_QUESTION_VALUES+=([$template_name]="${HOSTNAMELIST}")
						;;
					"dataone-cn-os-core/cn.nodeids")
						CN_NODEIDSLIST=(`xmlstarlet sel -t --match "//environment[@context='${CONTEXT}']/machine/question[@keyref='dataone-cn-os-core/cn.nodeid']"  --value-of "concat(text(), ' ')"  "$D1_CONF_DIR/${D1_DEB_CONF_XML}"`)
						join ';' ${CN_NODEIDSLIST[@]}
						NODEIDSLIST=${RTN_JOIN}
						
						db_get $template_name
						local DEB_NODEIDSLIST=$RET
						
						if [[ -n $DEB_NODEIDSLIST && $NODEIDSLISTT != $DEB_NODEIDSLIST ]]; then
							CHANGED_FLAG="true"
						fi	
						
						db_set $template_name ${NODEIDSLIST}
						# log "NODEIDSLIST ${NODEIDSLIST[@]}"
						DEB_QUESTION_VALUES+=([$template_name]="${NODEIDSLIST}")
						;;
					"dataone-cn-os-core/cn.context.label")
						db_get $template_name
						local DEB_CONTEXT=$RET
						if [[ -n $DEB_CONTEXT && DEB_CONTEXT != $CONTEXT ]]; then
							CHANGED_FLAG="true"
						fi
						db_set $template_name ${CONTEXT}
						# log "CONTEXT $CONTEXT"
						DEB_QUESTION_VALUES+=([$template_name]="${CONTEXT}")
						;;
					*)
						SEEN_FLAG="false"
						log "unable to process derived template $template_name."
						;;					
				esac
				db_fset $template_name seen $SEEN_FLAG
				XML_TEMPLATE_BOOLEAN[$SEEN]=$SEEN_FLAG
				db_fset $template_name derived-value  ${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}
				db_fset $template_name configured-value ${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}
				db_fset $template_name user-entered-value ${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}
				unset -v DEB_QUESTION_FLAGS[$template_name]
				DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
				DB_QUESTION_CHANGED+=([$template_name]="$CHANGED_FLAG")
			fi
		db_go
		fi
	done
	log "end process_derived_debian_config"
}

#####
##### process_create_debian_config()
##### This function will populate the debian backend db for the
##### first time during an install
#####
##### From the templates in the structure XML_QUESTION_VALUES that were
##### pulled from the xml file
##### populate the datastructures DEB_QUESTION_VALUES and DEB_QUESTION_FLAGS
##### to the reflect the state of the debian backend database
##### 
function process_create_debian_config()
{
	log "start process_create_debian_config"
	local TEMPLATE_VALUE
	local DB_VALUE
	local EXCEPTION_DB_VALUE
	#for each template in templates data structure, find out if DB 'seen' flag is false.
	#if seen is true, then accept the value as provided, or it's a noop (already configured by ansible).
	for template_name in ${!XML_QUESTION_VALUES[@]}
	do
		eval declare -a DEB_FLAG_BOOLEAN=("${DEB_QUESTION_FLAGS[$template_name]}")
		if [ "${DEB_FLAG_BOOLEAN[SEEN]}" == "false" ]; then
			eval declare -a XML_TEMPLATE_BOOLEAN=("${XML_TEMPLATE_FLAGS[$template_name]}")

			if [ "${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}" == "true" ]; then
				#if configured-value is true, then get the answer from the questions section for the machine/environment
				db_set $template_name "${XML_QUESTION_VALUES[$template_name]}"
				db_fset $template_name seen true
				XML_TEMPLATE_BOOLEAN[$SEEN]="true"
				db_fset $template_name derived-value  ${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}
				db_fset $template_name configured-value ${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}
				db_fset $template_name user-entered-value ${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}
				DEB_QUESTION_VALUES+=([$template_name]="${XML_QUESTION_VALUES[$template_name]}")
				log "XML_QUESTION_VALUES $template_name ${XML_QUESTION_VALUES[$template_name]}"
				unset -v DEB_QUESTION_FLAGS[$template_name]
				DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
				DB_QUESTION_CHANGED+=([$template_name]="false")
			elif [ "${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}" == "true" ]; then
			#if template flag user-entered-value is true, then prompt the user for input.
				if (db_input high "$template_name"); then
					db_go
				else
					## find if the value was set by some other system, such as ansible
					log "unable to update user-entered template $template_name"
					db_get $template_name
					EXCEPTION_DB_VALUE=$RET
					if [[ -z ${EXCEPTION_DB_VALUE} ]]; then
						# nothing else to do here but fail, db_input failed and the value is not set in debconf backend
						log "failed to retrieve user-entered template $template_name"
						exitWithFailureCode 86
					fi
				fi
				db_fset $template_name seen true
				XML_TEMPLATE_BOOLEAN[$SEEN]="true"
				db_fset $template_name derived-value  ${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}
				db_fset $template_name configured-value ${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}
				db_fset $template_name user-entered-value ${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}
				db_get $template_name
				TEMPLATE_VALUE=$RET
				DEB_QUESTION_VALUES+=([$template_name]="${TEMPLATE_VALUE}")
				log "USER ENTERED VALUE $template_name ${TEMPLATE_VALUE}"
				unset -v DEB_QUESTION_FLAGS[$template_name]
				DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
				DB_QUESTION_CHANGED+=([$template_name]="false")
			fi
		else
			### it already been seen, pull the DEB_QUESTION values from the database
			db_get $template_name
			local DB_VALUE=$RET
			log "SETTING DEB_QUESTION_VALUES $template_name $DB_VALUE"
			DEB_QUESTION_VALUES+=([$template_name]="${DB_VALUE}")
			DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
		fi
	done
	#if template flag derived-value is true, then ignore.(the derived templates will be processed after all other user-entered and configured values are set)
	process_derived_debian_config
	log "end process_create_debian_config"

}

#####
##### process_update_debian_config()
##### This function will update the debian backend db for 
##### anytime the package is upgraded
#####
##### From the templates in the structure XML_QUESTION_VALUES that were
##### pulled from the xml file
##### update the datastructures DEB_QUESTION_VALUES and DEB_QUESTION_FLAGS
##### to the reflect the state of the debian backend database
##### 
function process_update_debian_config()
{
	log "start process_update_debian_config"
	local OLD_DB_VALUE
	local NEW_DB_VALUE
	# for an update:
	# for each template in templates data structure, find out if DB 'seen' flag is false.
	# if 'seen' is true, then accept the value as provided, or it's a noop (already configured by ansible).
	for template_name in ${!XML_QUESTION_VALUES[@]}
	do
		eval local -a DEB_FLAG_BOOLEAN=("${DEB_QUESTION_FLAGS[$template_name]}")
		eval local -a XML_TEMPLATE_BOOLEAN=("${XML_TEMPLATE_FLAGS[$template_name]}")
		#if seen is false, then check other flag values:
		if [ "${DEB_FLAG_BOOLEAN[$SEEN]}" == "false" ]; then
			# if db has a user-entered-value flag true and the template user-entered-value is false, there is a discrepency between what is expected and what has
			# been stored. This happens if the user has overrided the default behaviour somehow
			db_get $template_name
			OLD_DB_VALUE=$RET
			if  [[ "$CONTEXT" != "CUSTOM" && "${DEB_FLAG_BOOLEAN[$USER_ENTERED_VALUE]}" == "true"  &&  "${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}" == "false" ]]; then
				# compare the values as stored in the  template and the db.
				if [[ "${OLD_DB_VALUE}" == "${XML_QUESTION_VALUES[$template_name]}" ]]; then
					log "USER ENTERED VALUE changed to TEMPLATE_VALUE $template_name ${XML_QUESTION_VALUES[$template_name]}"
					# if the values are the same then, leave values alone. 
					# update the flags in the db to coincide with the flag in the template, changed flag remains false for derived values.
					db_fset $template_name derived-value  ${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}
					db_fset $template_name configured-value ${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}
					db_fset $template_name user-entered-value ${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}
					if [ "${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}" == "false" ]; then
						db_fset $template_name seen true
						XML_TEMPLATE_BOOLEAN[$SEEN]="true"
					fi
					DEB_FLAG_BOOLEAN[$USER_ENTERED_VALUE]="false"
					unset -v DEB_QUESTION_FLAGS[$template_name]
					DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
					DB_QUESTION_CHANGED+=([$template_name]="false")
					DEB_QUESTION_VALUES+=([$template_name]="${XML_QUESTION_VALUES[$template_name]}")

				else
					#  if the values are different, then set the default value of the question from the one held by the db, and prompt the user,changed flag is true.
					#  report the flag values as they are held in the db

					if (db_input high "$template_name"); then
						db_go
					else
						log "failed to update user-entered template $template_name"
					fi
					db_fset $template_name seen true
					DEB_FLAG_BOOLEAN[$SEEN]="true"
					unset -v DEB_QUESTION_FLAGS[$template_name]
					DEB_QUESTION_FLAGS+=([$template_name]="${DEB_FLAG_BOOLEAN[@]}")
					db_get $template_name
					NEW_DB_VALUE=$RET
					if [[ "$OLD_DB_VALUE" == "$NEW_DB_VALUE" ]]; then
						DB_QUESTION_CHANGED+=([$template_name]="false")
					else
						DB_QUESTION_CHANGED+=([$template_name]="true")
					fi
					DEB_QUESTION_VALUES+=([$template_name]="${NEW_DB_VALUE}")
					# log "USER ENTERED VALUE entered $template_name $NEW_TEMPLATE_VALUE"
				fi
			fi
			
			# if xml and debian template flag is user-entered 
			if  [[ "${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}" == "true" ]]; then
           		# then set the default value of the question from the one held by the db
           		# and prompt the user, changed flag is true.
           		db_get $template_name
           		OLD_DB_VALUE=$RET
           		
				if (db_input high "$template_name"); then
					db_go
				else
					log "failed to update user-entered template $template_name"
				fi
				db_fset $template_name derived-value  ${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}
				db_fset $template_name configured-value ${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}
				db_fset $template_name user-entered-value ${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}
				db_fset $template_name seen true
				XML_TEMPLATE_BOOLEAN[$SEEN]="true"
				db_get $template_name
				NEW_DB_VALUE=$RET
				if [[ "$OLD_DB_VALUE" == "$NEW_DB_VALUE" ]]; then
					DB_QUESTION_CHANGED+=([$template_name]="false")
				else
					DB_QUESTION_CHANGED+=([$template_name]="true")
				fi
				DEB_QUESTION_VALUES+=([$template_name]="${NEW_DB_VALUE}")
				unset -v DEB_QUESTION_FLAGS[$template_name]
				DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
				# log "USER ENTERED VALUE entered $template_name $NEW_TEMPLATE_VALUE"
			fi
			# if configured-value is true, 
			if  [[ "${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}" == "true" ]]; then
				# then compare the template and db values,
				if [[ "${OLD_DB_VALUE}" != "${XML_QUESTION_VALUES[$template_name]}" ]]; then
					# if they are different update the db and set changed flag to true
					db_set $template_name ${XML_QUESTION_VALUES[$template_name]}
					db_fset $template_name derived-value  ${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}
					db_fset $template_name configured-value ${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}
					db_fset $template_name user-entered-value ${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}
					db_fset $template_name seen true
					XML_TEMPLATE_BOOLEAN[$SEEN]="true"
					DEB_QUESTION_VALUES+=([$template_name]="${XML_QUESTION_VALUES[$template_name]}")
					unset -v DEB_QUESTION_FLAGS[$template_name]
					DEB_QUESTION_FLAGS+=([$template_name]="${XML_TEMPLATE_BOOLEAN[@]}")
					DB_QUESTION_CHANGED+=([$template_name]="true")
					# log "TEMPLATE VALUE of $template_name ${XML_QUESTION_VALUES[$template_name]}"
				else
					DEB_QUESTION_VALUES+=([$template_name]="${OLD_DB_VALUE}")
					DB_QUESTION_CHANGED+=([$template_name]="false")
				fi
			fi
		else
			### it already been seen, pull the DEB_QUESTIONs from the database
			db_get $template_name
			local DB_VALUE=$RET
			# log "SETTING DEB_QUESTION_VALUES $template_name $DB_VALUE"
			DEB_QUESTION_VALUES+=([$template_name]="${DB_VALUE}")
		fi
	done
    process_derived_debian_config
	log "end process_update_debian_config"
}
#####
##### resetTemplateSeenFlag()
##### reset all the DEB_QUESTION_FLAGS that have seen set to true to false
##### needed for coordination with ansible
#####
function resetDebQuestionSeenFlag()
{
	for template_name in ${!DEB_QUESTION_FLAGS[@]}
	do
		eval local -a DEB_FLAG_BOOLEAN=("${DEB_QUESTION_FLAGS[$template_name]}")
		if [[ "${DEB_FLAG_BOOLEAN[$SEEN]}" == "true" &&  "$template_name" != "dataone-cn-os-core/cn.openldap.firstcn" ]]; then
			db_fset $template_name seen false
		fi
	done
		
}
#####
##### build_debianDB_template_data_structures()
##### read the flags from the debian backend db into bash datastructures
##### populating the DEB_QUESTION_VALUES will be performed later
#####
function build_debianDB_template_data_structures()
{
	if (debconf-show dataone-cn-os-core >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "before build_debianDB_template_data_structures"
	fi

	local -a DEBIAN_FLAGS
	local DEBIAN_FLAGS_STR

	for template_name in ${!XML_TEMPLATE_FLAGS[@]}
	do
		# note that the posistions of the flags in the array
		
		db_fget $template_name seen
		DEBIAN_FLAGS[$SEEN]=${RET}
		db_fget $template_name derived-value
		DEBIAN_FLAGS[$DERIVED_VALUE]=${RET}
		db_fget $template_name user-entered-value
		DEBIAN_FLAGS[$USER_ENTERED_VALUE]=${RET}
		db_fget $template_name configured-value
		DEBIAN_FLAGS[$CONFIGURED_VALUE]=${RET}

		join ' ' ${DEBIAN_FLAGS[@]}
		DEB_QUESTION_FLAGS+=([$template_name]="${RTN_JOIN}")
	done

}

#####
##### build_xml_template_data_structures()
##### read the values from the xml config file into bash datastructures
##### determines the ip of the machine
##### sets the context
#####
function build_xml_template_data_structures()
{
#	local MY_POSSIBLE_IPS=(`/sbin/ifconfig -a | grep -o -P 'inet\s((?!127\.0\.\d+\.\d+)(?:(?:[01]?\d?\d?|2[0-4]\d|25[0-5])\.?){4})' | awk '{ print $2 }'`)
	local MY_POSSIBLE_IPS=(`hostname --all-ip-addresses`)
    local ALL_ENVIRONMENT_IPS=(`xmlstarlet sel -t --match "//environment[@context != 'CUSTOM']/machine"  --value-of "concat(@ip, ' ')"  "${D1_CONF_DIR}/${D1_DEB_CONF_XML}"`)

    for i in ${MY_POSSIBLE_IPS[@]}
	do
		if [[ "${ALL_ENVIRONMENT_IPS[@]}" =~ "${i}" ]]; then
			IP_ADDRESS=${i}
		fi
	done
	log "build_xml_template_data_structures from ${MY_POSSIBLE_IPS[@]} found $IP_ADDRESS"
	
    # build the datastructure to hold information from the templates section of the xml file.
    # seen derived-value user-entered-value configured-value 
    local TEMPLATE_NAMES=(`xmlstarlet sel -t --match "//templates/template"  --value-of "concat(@key, ' ')"  "${D1_CONF_DIR}/${D1_DEB_CONF_XML}"`)

    
    if [ -n $IP_ADDRESS ]; then
		# The IP ADDRESS is found within the xml config file, therefore, we can continue to configure the system via xml configuration
    	for template_name in ${TEMPLATE_NAMES[@]}
    	 do
			# log "build_xml_template_data_structures found $template_name"
			eval local -A FLAG_VALUES=(`xmlstarlet sel -t --match "//templates/template[@key='${template_name}']/flag"  \
			--value-of "string('[')" --value-of "@name"  --value-of "string(']=\"')" \
			--value-of "node()" --value-of "string('\"')" -n \
			"${D1_CONF_DIR}/${D1_DEB_CONF_XML}"`)

			# log "build_xml_template_data_structures found $template_name ${!FLAG_VALUES[@]} ${FLAG_VALUES[@]}"
			XML_TEMPLATE_FLAGS+=([$template_name]="${FLAG_VALUES[seen]} ${FLAG_VALUES[derived-value]} ${FLAG_VALUES[user-entered-value]} ${FLAG_VALUES[configured-value]}")
			unset FLAG_VALUES
		done
    	# Determine the context from the ip address
		local CN_CONTEXT_LIST=(`xmlstarlet sel -t --match "//machine[@ip='${IP_ADDRESS}']"  --value-of " string('dataone-cn-os-core/cn.context.label ')" --value-of "parent::node()/@context" "${D1_CONF_DIR}/${D1_DEB_CONF_XML}"`)
		
		# Set the global context variable
		CONTEXT=${CN_CONTEXT_LIST[1]}
		XML_QUESTION_VALUES=([dataone-cn-os-core/cn.context.label]="$CONTEXT")
		# build the datastructure to hold information from the questions section of the xml file. or the value of 
		OLD_IFS=$IFS
		IFS=$'\n'
		eval XML_QUESTION_VALUES+=(`xmlstarlet sel -t --match "//environment[@context='${CONTEXT}']/question" --value-of "string('[')"  --value-of "@keyref" --value-of "string(']=\"')" --value-of "node()" --value-of "string('\"')" -n "$D1_CONF_DIR/${D1_DEB_CONF_XML}"`)
		eval XML_QUESTION_VALUES+=(`xmlstarlet sel -t --match "//machine[@ip='${IP_ADDRESS}']/question" --value-of "string('[')" --value-of "@keyref" --value-of "string(']=\"')" --value-of "node()" --value-of "string('\"')" -n "$D1_CONF_DIR/${D1_DEB_CONF_XML}"`)
		IFS=$OLD_IFS
	else
		# The IP ADDRESS was not found within the xml config file, therefore, we will build a CUSTOM installation in which the user must answer all the template questions
    	IP_ADDRESS=$(hostname -i)
    	CONTEXT="CUSTOM"
    	for template_name in ${TEMPLATE_NAMES[@]}
    	do
			XML_TEMPLATE_FLAGS+=([$template_name]="false false true false")
		done
    fi
    # XXX this is a hack for the time being. may need to add it to the template later
    # but it does not follow in the normal question/template fields of the
    # xml file
    db_set dataone-cn-os-core/cn.ipaddress "${IP_ADDRESS}" # clear the cached pw
	db_fset dataone-cn-os-core/cn.ipaddress seen true

}

#####
##### download_verify_config_xml()
##### attempt to download the configuration xml from the dataone releases website
##### also attempt to download the xml schema of the configuration file as well
##### if both downloads are successful, then validate the downloaded config xml 
##### and then copy over the configuration in /etc/dataone
##### if only the xml download is successful, then make certain it is wellformed
##### and then copy over the configuration in /etc/dataone
##### if neither download is successful, then the default
##### config xml in /etc/dataone will be used
#####
#####
function download_validate_config_xml()
{
	if (curl --silent --fail -o "${D1_TMP_DIR}/${D1_DEB_CONF_XML}" "${D1_DEB_CONF_XML_URL}" &>/dev/null ) && [ -e "${D1_TMP_DIR}/${D1_DEB_CONF_XML}" ]; then
	
		log "Downloaded ${D1_DEB_CONF_XML}"
		# Download the xml schema in order validate the xml file
		if (curl  --silent --fail -o "${D1_TMP_DIR}/${D1_DEB_XSD}" "${D1_DEB_XSD_URL}" &>/dev/null) && [ -e "${D1_TMP_DIR}/${D1_DEB_XSD}" ]; then
			### the val -b will print out the list of invalid xml files 
			### if files are valid, nothing will be returned
			if (xmlstarlet val -q -s "${D1_TMP_DIR}/${D1_DEB_XSD}" "${D1_TMP_DIR}/${D1_DEB_CONF_XML}" &>/dev/null); then
				log "${D1_DEB_CONF_XML} is valid"
				cp -f "${D1_TMP_DIR}/${D1_DEB_CONF_XML}" $D1_CONF_DIR
				log "copied ${D1_DEB_CONF_XML} to ${D1_CONF_DIR}"
			else
				log "invalid xml ${D1_DEB_CONF_XML} downloaded, using current version in ${D1_CONF_DIR} instead"
			fi
		else
			### Here we have downloaded the xml file, but the xsd download failed. 
			### We could just check the xml file for well-formedness and continue with the downloaded file
			### or we could ignore the downloaded xml and use the last known valid version in /etc/dataone
			log "unable to download ${D1_DEB_XSD} to validate ${D1_DEB_CONF_XML}"
			
			if (xmlstarlet val -q -w "${D1_TMP_DIR}/${D1_DEB_CONF_XML}" &>/dev/null); then
				log "${D1_DEB_CONF_XML} is wellformed."
				cp -f "${D1_TMP_DIR}/${D1_DEB_CONF_XML}" "${D1_CONF_DIR}/${D1_DEB_CONF_XML}"
				log "copied ${D1_DEB_CONF_XML} to ${D1_CONF_DIR}"
			else
				log "xml ${D1_DEB_CONF_XML} not well formed. Using current version in ${D1_CONF_DIR} instead"
			fi
		fi
	else
		log "Failure to download ${D1_DEB_CONF_XML}. use ${D1_CONF_DIR}/${D1_DEB_CONF_XML} instead"
	fi
}


#####
##### configure_node_property()
##### given a template_name, find the value that should be substituted in the properties file 
##### and perform the substitution
#####
function configure_node_property() 
{
  local TEMPLATE_NAME=$1
  local NODE_PROPS_FILE=$2
  local OVERRIDE=$3
  local NODE_VALUE
  
  if [ -e ${NODE_PROPS} ]; then
    # Fetch the context's node id list from the debconf database
    if [ -z "$OVERRIDE" ]; then
      NODE_VALUE=${DEB_QUESTION_VALUES[dataone-cn-os-core/$TEMPLATE_NAME]}
    else
      NODE_VALUE=$OVERRIDE
    fi
    sed -i.bak "s/\(${TEMPLATE_NAME} *=\).*/\1${NODE_VALUE}/i" ${NODE_PROPS_FILE}
  else
    log "The file ${NODE_PROPS} must be in place to proceed."
    exitWithFailureCode 64
  fi
}
#####
##### configure_node_property()
##### the /etc/dataone/node.properties file is configured per machine. 
##### The values are pulled out of the debian database and 
##### substituted for tokens found in the properties file
#####
function configure_node_properties_file()
{
	local NODE_PROPS="$D1_CONF_DIR/node.properties"
	
	configure_node_property "cn.context.label" $NODE_PROPS
	
	local SYNCHRONIZED=${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.synchronized]}
			
	if [[ "${SYNCHRONIZED}" != *false* ]];then
		configure_node_property "cn.iplist" $NODE_PROPS
	else
		configure_node_property "cn.iplist" $NODE_PROPS "127.0.0.1"
	fi
	
	configure_node_property "cn.nodeids" $NODE_PROPS
	configure_node_property "cn.nodeid" $NODE_PROPS
	configure_node_property "cn.router.nodeId" $NODE_PROPS
	configure_node_property "cn.router.hostname" $NODE_PROPS
	
	local HOST_NAME=${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.router.hostname]}
	PUBLICCERT_VALUE=${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.publiccert.filename]}
	CERT_FILE_PATH=${SERVER_SSL_PREFIX_DIR}/${HOST_NAME}/${PUBLICCERT_VALUE}
	CERT_FILE_PATH_ESC=${CERT_FILE_PATH//\//\\\/}
	log "Public cert filename is: ${CERT_FILE_PATH_ESC}"
	configure_node_property "cn.server.publiccert.filename" $NODE_PROPS "${CERT_FILE_PATH_ESC}"
  
	log "Start configuration of D1Client certificate"
	CLIENT_CERT_FILE_LABEL="D1Client.certificate.filename"
	if [[  -e ${NODE_PROPS} && "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.filename]}" != "false" ]]; then
		# Change the property of D1Client certificate filename to the one accepted during configuration
	
		if ! (sed -i.bak "s/\(${CLIENT_CERT_FILE_LABEL} *=\).*/\1${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.filename]}/" ${NODE_PROPS} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Error Unable to modify ${CLIENT_CERT_FILE_LABEL} in ${D1_LOG_DIR}/${D1_LOG_FILE}"
		fi
	else
		log "Client cert filename is missing. Must set ${CLIENT_CERT_FILE_LABEL} in ${NODE_PROPS} for SSL to function properly"
	fi
	
	if ! (sed -i.bak "s/SOLRTOKEN/${SOLR_TOKEN}/" ${NODE_PROPS} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Error Unable to modify SOLRTOKEN in ${NODE_PROPS}"
	fi
	
	if ! (sed -i.bak "s/CN_ENV_HOSTNAME_LIST/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.hostnamelist]}/" ${NODE_PROPS} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
        log "Error Unable to modify CN_ENV_HOSTNAME_LIST in ${NODE_PROPS}"
    fi
	
	log "Start configuration of Hostname in ${NODE_PROPS}"
	# set the FQDN of the machine
	if [ -n "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.hostname]}" ]; then
		if ! (sed -i.bak  "s/SERVER_NAME/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.hostname]}/" ${NODE_PROPS} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Error Unable to modify SERVER_NAME in ${NODE_PROPS}"
		fi
	else
	  log "dataone-cn-os-core/cn.hostname can not be set in ${NODE_PROPS}"
	fi
}

#####
##### configure_certificates()
##### make certain that the x509 certificate and keys are in the
##### correct subjectory with the correct permissions
#####
function configure_certificates()
{
	log "Start configuration of DataONE CN client certificate"
	
	##################################################################
	# Check the dataone client certificate provided by the user
	# This certificate can not be added to the SVN repository because it is not
	# secure to do so; it includes the public and private key
	# -- access to the file must be restricted
	##################################################################
	if [ ! -e "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.filename]}" ]; then
		log "Client cert file is missing.  Please provide it as ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.filename]}. 
		Without this, SSL will not function properly."
		exitWithFailureCode 62
	fi
	
	##################################################################
	# Check the dataone private key provided by the user
	# This key can not be added to the SVN repository because it is not
	# secure to do so -- access to the file must be restricted
	##################################################################
	# check if this is a new install
		
	log "Start configuration of DataONE private key"
	local HOST_NAME=${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.router.hostname]}
	if [ ! -e "${SERVER_SSL_PREFIX_DIR}/${HOST_NAME}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.privatekey.filename]}" ];then
		log "Key file is missing.  Please provide it as ${SERVER_SSL_PREFIX_DIR}/${HOST_NAME}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.privatekey.filename]}. Without
		this, SSL will not function properly."
		exitWithFailureCode 63
	fi
	
	if [ ! -e "${SERVER_SSL_PREFIX_DIR}/${HOST_NAME}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.publiccert.filename]}" ]; then
		log "Server Public Certificate file is missing.  Please provide it as ${SERVER_SSL_PREFIX_DIR}/${HOST_NAME}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.publiccert.filename]}. Without
		this, SSL will not function properly."
		exitWithFailureCode 64
	fi
	# set permissions correctly for the certs and private dirs
	if [ -d  ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]} ] && [ -d ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]} ]; then
		if ! (chown -R ${TOMCAT_USER}:ssl-cert ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Error Unable to chown on ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}"
		fi
		if ! (chown -R ${TOMCAT_USER}:ssl-cert ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Error Unable to chown on ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}"
		fi
	else
		log "either ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]} or ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]} is missing. Much will fail after this install process"
	fi	
	
}
#####
##### configure_ufw()
##### set up the Coordinating Node firewall
#####
function configure_ufw()
{
	log "Start configuration of  UFW"
	###############################################################################
	# Configure UFW
	###############################################################################
	
	#open up the correct ports
	
	if [[ "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.iplist]}" == [1-9]* ]]; then
		for IP in ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.iplist]}
			do
				if [[ "${IP}" != "${IP_ADDRESS}" ]]; then
					# ldap syncrepl
					if ! (ufw allow to any port 389 from ${IP} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
						log "Error Unable to allow ufw 389 from ${IP}"
					fi
					log "Added 'ufw allow to any port 389 from ${IP}' rule"
				fi
			done
	fi
	if ! (ufw allow ssh >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Error Unable to allow ufw ssh"
		exitWithFailureCode 65
	fi # critical for remote management, don't remove
	if ! (ufw allow http >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Error Unable to allow ufw http"
		exitWithFailureCode 66
	fi
	if ! (ufw allow https >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Error Unable to allow ufw https"
		exitWithFailureCode 67
	fi
	MONITOR_HOST=$(nslookup monitor.dataone.org | grep Add | grep -v '#' | cut -f 2 -d ' ')
	if ! (ufw allow from ${MONITOR_HOST} to any port 6556 >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Error Unable to allow from ${MONITOR_HOST} to any port 6556"
	fi
    
}

#####
##### install_configure_jdk
##### install and configure the jdk
##### 
function configure_jdk() {
    log "configure default java, java and keytool"
    update-alternatives --set java ${JDK_HOME}/jre/bin/java
    update-alternatives --set javac ${JDK_HOME}/bin/javac
    update-alternatives --set keytool ${JDK_HOME}/jre/bin/keytool
    #update-alternatives --set javaws ${JDK_HOME}/jre/bin/javaws
    log "set the defaul-java to openjdk 8"
    rm -rf $DEFAULT_JAVA_HOME
    ln -s  $JDK_HOME $DEFAULT_JAVA_HOME
}

#####
##### configure_keystore()
##### import certificates into the java keystore
##### 

function configure_keystore()
{
	###############################################################################
	# Configure Java keystore with GoDaddy and DataONE CA
	###############################################################################
	# Get the password

	local JAVA_KEYSTORE_PASSWORD="${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.keystore.password]}"

	# output from keytool is piped to exit 0 so that if keytool fails due to the file already having
	# been added then the postinst script does not fail due to the subshell failing
	# After we switched to use LE certificates, it is not necessary to import its certificates to the java key store anymore since they are there.
	#local INTERMEDIATE_BUNDLE="${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.cachain.filename]}"
	
	#log "Attempting to remove ${SSL_CERT_DIR}/${INTERMEDIATE_BUNDLE} from Java keystore: ${JAVA_KEYSTORE}"
	#(keytool -delete -noprompt -alias ${INTERMEDIATE_BUNDLE} -keystore ${JAVA_KEYSTORE} -storepass ${JAVA_KEYSTORE_PASSWORD} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 | exit 0)
	
	#log "Adding ${SSL_CERT_DIR}/${INTERMEDIATE_BUNDLE} to Java keystore: ${JAVA_KEYSTORE}"
	#(keytool -importcert -noprompt -alias ${INTERMEDIATE_BUNDLE} -file ${SSL_CERT_DIR}/${INTERMEDIATE_BUNDLE} -keystore ${JAVA_KEYSTORE} -storepass ${JAVA_KEYSTORE_PASSWORD} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 | exit 0)
	
	# get the DataONE CA
	
	(keytool -importcert -noprompt -alias DataONECA -file ${SSL_CERT_DIR}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.dataone.ca.filename]} -keystore ${JAVA_KEYSTORE} -storepass ${JAVA_KEYSTORE_PASSWORD}  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 | exit 0)
	log "Adding ${SSL_CERT_DIR}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.dataone.ca.filename]} to Java keystore: ${JAVA_KEYSTORE} -$RTN_KEYTOOL"
	# Always clear the cached keystore password
	db_set dataone-cn-os-core/cn.keystore.password "" # clear the cached pw
	db_fset dataone-cn-os-core/cn.keystore.password seen false
	eval local -a DEB_FLAG_BOOLEAN=("${DEB_QUESTION_FLAGS[dataone-cn-os-core/cn.keystore.password]}")
	DEB_FLAG_BOOLEAN[$SEEN]="false"
	unset -v DEB_QUESTION_FLAGS[dataone-cn-os-core/cn.keystore.password]
	DEB_QUESTION_FLAGS+=([dataone-cn-os-core/cn.keystore.password]="${DEB_FLAG_BOOLEAN[@]}")

}

#####
##### configure_apache()
##### modify apache configuration files to allow for dataone operations
##### such as ssl 
#####
function configure_apache()
{
	###############################################################################
	# Configure Apache
	###############################################################################
	
	## Stop apache
	log "Stopping Apache"
	if (pidof apache2  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		if ! (/etc/init.d/apache2 stop >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Error Unable to stop apache"
			exitWithFailureCode 68
		fi
	fi 
	## change the available port 80 only to localhost
	if [ -e ${APACHE_CONF_DIR}/ports.conf ]; then 
		## if ports.conf has *:80 as its NameVirtualHost, then change it to 127.0.0.1:80
		if (egrep -q 'NameVirtualHost[[:space:]]+\*:80' ${APACHE_CONF_DIR}/ports.conf); then
			if ! (sed -i.bak --regexp-extended 's/(NameVirtualHost[[:space:]]+)\*:80/\1127.0.0.1:80/;' ${APACHE_CONF_DIR}/ports.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify NameVirtualHost in ${APACHE_CONF_DIR}/ports.conf"
			fi
		fi
	fi
	## make certain we have a directory for the JKMount directives of our apps
	if [ ! -d ${APACHE_CONF_DIR}/jk_mount ]; then
		if ! (mkdir -p ${APACHE_CONF_DIR}/jk_mount >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to mkdir ${APACHE_CONF_DIR}/jk_mount"
		fi
		if ! (chmod 750 ${APACHE_CONF_DIR}/jk_mount >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to chmod ${APACHE_CONF_DIR}/jk_mount"
		fi
	fi
	
	## if the jk.conf file has changed then copy in a new jk.conf file
	if [ -e ${APACHE_CONF_DIR}/mods-available/jk.conf ]; then 
		## if there is a difference, then the diff script returns false
		if ! (diff ${SCRIPT_DIR}/jk.conf ${APACHE_CONF_DIR}/mods-available/jk.conf); then
			log "Backing up ${APACHE_CONF_DIR}/mods-available/jk.conf to ${APACHE_CONF_DIR}/mods-available/jk.conf.${LONG_DATE}"
			if ! (mv ${APACHE_CONF_DIR}/mods-available/jk.conf ${APACHE_CONF_DIR}/mods-available/jk.conf.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to move ${APACHE_CONF_DIR}/mods-available/jk.conf ${APACHE_CONF_DIR}/mods-available/jk.conf.${LONG_DATE}"
			fi
		fi
	fi
	log "Copying jk.conf to ${APACHE_CONF_DIR}/mods-available/"
	if ! (cp ${SCRIPT_DIR}/jk.conf ${APACHE_CONF_DIR}/mods-available/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy ${SCRIPT_DIR}/jk.conf to ${APACHE_CONF_DIR}/mods-available/"
	fi
	
	## copy in workers.properties file for mod-jk
	if [ -e ${MOD_JK_CONF_DIR}/workers.properties ]; then
		## if there is a difference, then the diff script returns false
		if ! (diff ${SCRIPT_DIR}/workers.properties ${MOD_JK_CONF_DIR}/workers.properties); then
			if [ -n "${WORKERS_PROPS_DIFF}" ]; then
				log "Backing up ${MOD_JK_CONF_DIR}/workers.properties to ${MOD_JK_CONF_DIR}/workers.properties.${LONG_DATE}"
				if ! (mv ${MOD_JK_CONF_DIR}/workers.properties ${MOD_JK_CONF_DIR}/workers.properties.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "Unable to move ${MOD_JK_CONF_DIR}/workers.properties to ${MOD_JK_CONF_DIR}/workers.properties.${LONG_DATE}"
				fi
			fi
		fi
	fi
	log "Copying workers.properties to ${MOD_JK_CONF_DIR}/"
	if ! (cp ${SCRIPT_DIR}/workers.properties ${MOD_JK_CONF_DIR}/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy ${SCRIPT_DIR}/workers.properties to ${MOD_JK_CONF_DIR}/"
	fi
	
	log "Copying qos to ${APACHE_CONF_DIR}/mods-available/"
	if ! (cp ${SCRIPT_DIR}/qos.conf ${APACHE_CONF_DIR}/conf-available/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy ${SCRIPT_DIR}/qos.conf to ${APACHE_CONF_DIR}/conf-available/"
	fi
	log "Copying mod_qos_500_error.xml to ${APACHE_CONF_DIR}/mods-available/"
	if ! (cp ${SCRIPT_DIR}/mod_qos_500_error.xml ${APACHE_WWW_DIR}/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy ${SCRIPT_DIR}/mod_qos_500_error.xml to ${APACHE_WWW_DIR}/"
	fi
	
	## disable and then re-enable mod_proxy, mod_rewrite, cache_disk, and mod_headers
	log "Refreshing Proxy"	
	if ! (a2dismod proxy_ajp >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable proxy_ajp apache module"
	fi
	if ! (a2dismod proxy_http >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable proxy_http apache module"
	fi
	if ! (a2dismod proxy >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable proxy apache module"
	fi
	
	if ! (a2enmod proxy >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to enable proxy apache module"
	fi
	if ! (a2enmod proxy_http >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to enable proxy_http apache module"
	fi
	if ! (a2enmod proxy_ajp >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then   
		log "Unable to ensable proxy_ajp apache module"
	fi
	
	log "Refreshing Rewrite"
	if ! (a2dismod rewrite >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable rewrite apache module"
	fi
	if ! (a2enmod rewrite >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to ensable rewrite apache module"
	fi
	
	log "Refreshing Headers"
	if ! (a2dismod headers >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable headers apache module"
	fi
	if ! (a2enmod headers >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to ensable headers apache module"
	fi
	
	log "Refreshing Cache module"
	if ! (a2dismod cache_disk >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable apache disk_cache module"
	fi
	if ! (a2enmod cache_disk >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to enable apache disk_cache module"
	fi
	
	# Turn on the ssl module
	log "Refreshing Mod SSL"
	if ! (a2dismod ssl >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable ssl site"
	fi
	if ! (a2enmod ssl >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to enable ssl site"
	fi
	
	## disable  mod qos since there are some syntax issues coming form PPA apache
	log "Refreshing Mod QoS"
	if ! (a2dismod qos >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable mod qos"
	fi
	## disable and then re-enable mod jk to pick up changes
	log "Refreshing Mod JK"
	if ! (a2dismod jk >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable jk apache site"
	fi
	if ! (a2enmod jk >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to enable jk apache site"
	fi
	## disable and then re-enable mod expires to pick up changes
	log "Refreshing Mod Expires"
	if ! (a2dismod expires >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable mod expires"
	fi
	if ! (a2enmod expires >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to enable mod expires"
	fi

	## disable the default apache site, which gets in the way of the other sites
	if ! (a2dissite 000-default >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to disable  000-default apache site"
	fi
	
	## mod_qos needs to be modified to add in exclusions for all the CNs
	# in this environment
	local MOD_QOS_CN_EXCLUSIONS="\n"
	if [[ "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.iplist]}" == [1-9]* ]]; then
		for IP in ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.iplist]}
			do
				MOD_QOS_CN_EXCLUSIONS+="\tQS_SrvMaxConnExcludeIP\t${IP}\n"
			done
		if ! (sed -i  's/CN_QS_SRVMAXCONNEXCLUDEIP/'${MOD_QOS_CN_EXCLUSIONS}'/' ${APACHE_CONF_DIR}/conf-available/qos.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to configure apache mod_qos to exclude CNs"
		fi
	fi
	
	## copy in site configuration files
	for SITE in ${SITES}
	do
		if [ -e "${APACHE_CONF_DIR}/sites-available/${SITE}.conf" ]; then 
		  ## if there is a difference, then the diff script returns false
		  if ! (diff ${SCRIPT_DIR}/${SITE}.conf ${APACHE_CONF_DIR}/sites-available/${SITE}.conf); then
			log "Backing up ${APACHE_CONF_DIR}/sites-available/${SITE}.conf to ${APACHE_CONF_DIR}/sites-available/${SITE}.conf.${LONG_DATE}"
			if ! (mv ${APACHE_CONF_DIR}/sites-available/${SITE}.conf ${APACHE_CONF_DIR}/sites-available/${SITE}.conf.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to move  ${APACHE_CONF_DIR}/sites-available/${SITE}.conf ${APACHE_CONF_DIR}/sites-available/${SITE}.conf.${LONG_DATE}"
			fi
		  fi
		fi
		log "Copying ${SITE}.conf site file to ${APACHE_CONF_DIR}/sites-available/"
		if ! (cp ${SCRIPT_DIR}/${SITE}.conf ${APACHE_CONF_DIR}/sites-available/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to copy  ${SCRIPT_DIR}/${SITE}.conf ${APACHE_CONF_DIR}/sites-available/"
			continue
		fi
		
		## replace the token SERVER_NAME in the site file
		
		if [ -n ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.router.hostname]} ]; then
			if ! (sed -i.bak  's/SERVER_NAME/'${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.router.hostname]}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify SERVER_NAME in ${SITE}.conf Apache"
			fi
		else
				log "dataone-cn-os-core/cn.router.hostname can not be set in ${APACHE_CONF_DIR}/sites-available/${SITE}.conf"
		fi
		
		## replace the token SERVER_ALIAS in the site file
		
		if [ -n ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.hostname]} ]; then
			if ! (sed -i.bak  's/SERVER_ALIAS/'${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.hostname]}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify SERVER_ALIAS in ${SITE}.conf Apache"
			fi
		else
				log "dataone-cn-os-core/cn.hostname can not be set in ${APACHE_CONF_DIR}/sites-available/${SITE}.conf"
		fi
		
		## replace the token SEARCH_SERVER_NAME in the site file
		
		if [ -n ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.search.hostname]} ]; then
			if ! (sed -i.bak  's/SEARCH_HOSTNAME/'${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.search.hostname]}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify SEARCH_NAME in ${SITE}.conf Apache"
			fi
		else
				log "dataone-cn-os-core/cn.router.hostname can not be set in ${APACHE_CONF_DIR}/sites-available/${SITE}.conf"
		fi
		
		## Set the server side SSL CA bundle
		#local INTERMEDIATE_BUNDLE="${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.cachain.filename]}"

		#if ! (sed -i.bak  's/INTERMEDIATE_BUNDLE/'${INTERMEDIATE_BUNDLE}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			#log "Unable to modify INTERMEDIATE_BUNDLE in ${SITE}.conf Apache"
		#fi

		
		## Set the client side SSL CA chain file            
		if ! (sed -i.bak  's/D1_CHAIN_FILE/'${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.dataone.ca.filename]}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to modify D1_CHAIN_FILE in ${SITE}.conf Apache"
		fi
		
		## Set the client side SSL certificate file            
		if ! (sed -i.bak  's/CN_HOSTNAME/'${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.router.hostname]}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to modify PUBLIC_SERVER_CERT_FILE in ${SITE}.conf Apache"
		fi
		
		## Set the client side SSL private key file      
		if ! (sed -i.bak  's/D1_PRIVATEKEY_FILE/'${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.server.privatekey.filename]}'/' ${APACHE_CONF_DIR}/sites-available/${SITE}.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to modify D1_PRIVATEKEY_FILE in ${SITE}.conf Apache"
		fi
		
		## enable ${SITE} site
		log "Enabling ${SITE} site"
		if ! (a2dissite ${SITE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to disable ${SITE} Apache!"
		fi
		if ! (a2ensite ${SITE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to enable ${SITE} Apache!"
		fi
	
	done
	## Start Apache
	if ! (/etc/init.d/apache2 start >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to Start Apache!"
		exitWithFailureCode 69
	fi

}
#####
##### configure_tomcat()
##### modify tomcate configuration files to allow for dataone operations
#####
function configure_tomcat()
{

	# findout if tomcat is running
	if (systemctl status ${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		## Stop tomcat
		log "Stopping Tomcat"
		if ! (systemctl stop ${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to Stop Tomcat!"
			exitWithFailureCode 70
		fi
	fi
	
	
	
	if [ -e "/etc/default/${TOMCAT}" ]; then
		if ! (egrep -q '^\#?JAVA_OPTS\=".+\-XX\:\+UseConcMarkSweepGC"' /etc/default/${TOMCAT}); then
			if ! (egrep -q 'JAVA_OPTS\=.+\-XX\:\+UseParallelGC' /etc/default/${TOMCAT}); then
				echo "JAVA_OPTS=\"\${JAVA_OPTS} -XX:+UseParallelGC\"" >> /etc/default/${TOMCAT}
			fi
		else 
			if ! (egrep -q 'JAVA_OPTS\=.+\-XX\:\+UseParallelGC' /etc/default/${TOMCAT}); then
				## XXX   XXX   XXX   -RPW
				## What happens if UseConcMarkSweepGC is not a part of JAVA_OPTS, but we still want to include
				## UseParallelGC as our main garbage collection method
				if ! (sed -i.bak --regexp-extended s/UseConcMarkSweepGC/UseParallelGC/ /etc/default/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "Unable to modify UseConcMarkSweepGC in /etc/default/${TOMCAT}"
				fi
				if ! (rm /etc/default/${TOMCAT}.bak >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "Unable to remove /etc/default/${TOMCAT}.bak"
				fi
			fi
		fi
		
		if ! (egrep -q 'JAVA_OPTS\=.+\-XX\:MaxPermSize' /etc/default/${TOMCAT}); then
				## THE MAIN PROBLEM WITH THIS APPROACH CURRENTLY IS SUPPORTING THE DIFFERENT ENVIRONEMENTS
				## developer VMs will not be able to support this amount of heap space
				## in fact our development environment probably cannot
				log "Can't find the memory setting on /etc/default/${TOMCAT}, then set them."
				if ! (sed -i.bak --regexp-extended '0,/(^JAVA_OPTS\=)"([^"]*)"/s//\1"\2 -Xmx8192M -Xms1024M -XX:MaxPermSize=512M"/;' /etc/default/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "Unable to modify heap space settings in /etc/default/${TOMCAT}"
				fi
		fi
		
	fi
	## copy in jk.conf file
	if [ -e "${TOMCAT_HOME}/conf/server.xml" ]; then 
		## if there is a difference, then the diff script returns false
		if ! (diff ${SCRIPT_DIR}/server.xml ${TOMCAT_HOME}/conf/server.xml); then
			log "Backing up ${TOMCAT_HOME}/conf/server.xml to ${TOMCAT_HOME}/conf/server.xml.${LONG_DATE}"
			if ! (mv ${TOMCAT_HOME}/conf/server.xml ${TOMCAT_HOME}/conf/server.xml.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to move ${TOMCAT_HOME}/conf/server.xml to ${TOMCAT_HOME}/conf/server.xml.${LONG_DATE}"
			fi
		fi
	fi
	log "Copying server.xml to ${TOMCAT_HOME}/conf/"
	if ! (cp ${SCRIPT_DIR}/server.xml ${TOMCAT_HOME}/conf/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy  ${SCRIPT_DIR}/server.xml ${TOMCAT_HOME}/conf/"
	fi
	
	
	## add slash-handling properties to catalina.properties file
	## (tomcat doesn't support include, so need to add it to the main file)
	if [ -e "${TOMCAT_HOME}/conf/catalina.properties" ]; then
		if ! (grep -q 'ALLOW_ENCODED_SLASH' ${TOMCAT_HOME}/conf/catalina.properties); then
			
			if ! (cp ${TOMCAT_HOME}/conf/catalina.properties ${TOMCAT_HOME}/conf/catalina.properties.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to copy  ${TOMCAT_HOME}/conf/catalina.properties to ${TOMCAT_HOME}/conf/catalina.properties.${LONG_DATE} "
			fi
			log Appending slash-handling Java system properties to  ${TOMCAT_HOME}/conf/catalina.properties
			echo >> ${TOMCAT_HOME}/conf/catalina.properties
			echo \# Dataone configuration for handling encoded slash and backslashes >> ${TOMCAT_HOME}/conf/catalina.properties
			echo org.apache.tomcat.util.buf.UDecoder.ALLOW_ENCODED_SLASH=true >> ${TOMCAT_HOME}/conf/catalina.properties
			echo org.apache.catalina.connector.CoyoteAdapter.ALLOW_BACKSLASH=true >> ${TOMCAT_HOME}/conf/catalina.properties
		fi
	fi
	
	if ! (chown -R ${TOMCAT_USER}:${TOMCAT_USER} /etc/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to chown on /etc/${TOMCAT}"
	fi
	if ! (chown -R ${TOMCAT_USER}:${TOMCAT_USER} /var/lib/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to chown on /var/lib/${TOMCAT}"
	fi
	if ! (chown -R ${TOMCAT_USER}:${TOMCAT_USER} /var/log/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to chown on /var/log/${TOMCAT}"
	fi
	if ! (chown -R ${TOMCAT_USER}:${TOMCAT_USER} /var/cache/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to chown on /var/cache/${TOMCAT}"
	fi
	if ! (chown -R ${TOMCAT_USER}:${TOMCAT_USER} /usr/share/${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to chown on /usr/share/${TOMCAT}"
	fi
	
	log "Add the log4j safeguard"
    if grep -q "log4j2.formatMsgNoLookups" /etc/default/${TOMCAT}; then
      log "${LOG4J} exists in /etc/default/${TOMCAT} and don't need to do anything."  
   else
      log "${LOG4J} doesn't exist /etc/default/${TOMCAT} and we need to add it."
      JAVA_OPTS='${JAVA_OPTS}'
      sudo sed -i "$ a\\JAVA_OPTS=\"${JAVA_OPTS} ${LOG4J}\"" /etc/default/${TOMCAT}
   fi

}
#####
##### configure_openldap()
##### modify openldap configuration files to allow for dataone operations
##### populate the LDAP database for firsttime operations
##### the script will generate ldif configuration files based on
##### /etc/ldap/slapd.conf 
#####
function configure_openldap()
{
	###############################################################################
	# Configure OpenLDAP
	###############################################################################
	## Only populate LDAP on first run, otherwise migrate
	log "Configuring OpenLDAP"
	local ADDRESSES
	local DATAONE_CA_FILEPATH
	local LDAP_CERTIFICATE
	local LDAP_PRIVATEKEY
	local SYNC_SETTINGS
	local SYNC_CONF
	local MIGRATE_VERSION=0
	local OPENLDAP_POPULATED

    local return_val
    
	db_get dataone-cn-os-core/cn.openldap.populated
	OPENLDAP_POPULATED=$RET
	if [ -n "$ARG_VERSION" ]; then
		MIGRATE_VERSION=$ARG_VERSION
	fi
	if [ -e "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.certificate.filename]}" ]; then
		LDAP_CERTIFICATE="${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.certificate.filename]}"
		LDAP_CERTIFICATE=${LDAP_CERTIFICATE//\//\\\/}
	else
	  log "unable to locate ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.certificate.filename]}"
	  
	  exitWithFailureCode 94
	fi
	if [ -e "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.privatekey.filename]}" ]; then
		LDAP_PRIVATEKEY="${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.privatekey.filename]}"
		LDAP_PRIVATEKEY=${LDAP_PRIVATEKEY//\//\\\/}
    else
      log "unable to locate ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.privatekey.filename]}"
      exitWithFailureCode 95
	fi
	#
	#  CN Service and D1-Processing needs the ldap password in a properties
	# file so that they may connect to ldap to retrieve information
	# the migrate perl scripts need the values in the properties file too in order to connect to ldap
	#
	if ! (cp ${SCRIPT_DIR}/ldapService.properties ${D1_CONF_DIR}/ldapService.properties >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to copy ${SCRIPT_DIR}/ldapService.properties to ${D1_CONF_DIR}/ldapService.properties"
		exitWithFailureCode 96
	fi
	if ! (sed -i.bak "s/PASSWORD/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.password]}/" ${D1_CONF_DIR}/ldapService.properties >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to change the ldap admin password in ${D1_CONF_DIR}/ldapService.properties"
		exitWithFailureCode 97
	fi
	if ! (chown ${TOMCAT_USER}:${TOMCAT_USER} ${D1_CONF_DIR}/ldapService.properties >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to chown on ${D1_CONF_DIR}/ldapService.properties"
	fi
	if ! (chmod -R 640 ${D1_CONF_DIR}/ldapService.properties >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to chmod on ${D1_CONF_DIR}/ldapService.properties"
	fi
	### modify the migration scripts
	### considering the perl scripts are not used now. comment out the 
	### use of the perl scripts. IF a need arises in the future
	### to modify LDAP because of a migration issue, then the
	### scripts will need to be revisited/refactored
	### https://redmine.dataone.org/issues/6874
#	if [ -n "$LDAP_CERTIFICATE" ]; then
#			if ! (sed -i.bak "s/^\(ldap_repl_pem\)/my \$\1=\"${LDAP_CERTIFICATE}\";/" ${SCRIPT_DIR}/ldap/migrateLdap.pl  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
#				log "Unable to modify ldap_repl_pem value in ${SCRIPT_DIR}/ldap/migrateLdap.pl "
#			fi
#			if ! (sed -i.bak "s/^\(ldap_repl_pem\)/my \$\1=\"${LDAP_CERTIFICATE}\";/" ${SCRIPT_DIR}/ldap/prepareMigrateLdap.pl  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
#				log "Unable to modify ldap_repl_pem value in ${SCRIPT_DIR}/ldap/prepareMigrateLdap.pl "
#			fi
#	fi
#	if [ -n "$LDAP_PRIVATEKEY" ]; then
#			if ! (sed -i.bak "s/^\(ldap_repl_key\)/my \$\1=\"${LDAP_PRIVATEKEY}\";/" ${SCRIPT_DIR}/ldap/migrateLdap.pl  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
#				log "Unable to modify ldap_repl_key  value in ${SCRIPT_DIR}/ldap/migrateLdap.pl "
#				exitWithFailureCode 98
#			fi
#			if ! (sed -i.bak "s/^\(ldap_repl_key\)/my \$\1=\"${LDAP_PRIVATEKEY}\";/" ${SCRIPT_DIR}/ldap/prepareMigrateLdap.pl  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
#				log "Unable to modify ldap_repl_key  value in ${SCRIPT_DIR}/ldap/prepareMigrateLdap.pl "
#				exitWithFailureCode 99
#			fi
#	fi
#	
#	log "Preparing for Migrating all dataone schema specific entries"
#	if ! (${SCRIPT_DIR}/ldap/prepareMigrateLdap.pl --version $MIGRATE_VERSION>> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 ); then
#		exitWithFailureCode 82
#	fi

# for 1.2.0 remove dependency on dataone.schema changes
#	if [ -e "${LDAP_CONF_DIR}/schema/dataone.schema" ]; then 
#		if ! (diff ${SCRIPT_DIR}/ldap/dataone.schema ${LDAP_CONF_DIR}/schema/dataone.schema); then
#			log "Schema changing: Run the pre migration script"
#			if (pidof slapd  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
#			  log "Preparing for Migrating all dataone schema specific entries"
#			  if ! (${SCRIPT_DIR}/ldap/prepareMigrateLdap.pl --version $MIGRATE_VERSION>> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 ); then
#				exitWithFailureCode 82
#			  fi
#			else
#			  log "No migration. Ldap Not running"
#			fi
#			
#			log "Backing up ${LDAP_CONF_DIR}/schema/dataone.schema to ${LDAP_CONF_DIR}/schema/dataone.schema.${LONG_DATE}"
#			if ! (mv ${LDAP_CONF_DIR}/schema/dataone.schema ${LDAP_CONF_DIR}/schema/dataone.schema.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
#				log "Unable to move ${LDAP_CONF_DIR}/schema/dataone.schema to ${LDAP_CONF_DIR}/schema/dataone.schema.${LONG_DATE}"
#			fi
#		fi
#	fi
	## place schema extension

	if [ -z "${OPENLDAP_POPULATED}" ] || [ "${OPENLDAP_POPULATED}" == "false" ]; then
		confirm_ldap_running
		return_val=$?
		if [ "$return_val" -ne "$SUCCESS" ]
		then
			log "Slapd is not running and cannot be restarted. Failure!"
			exitWithFailureCode 90
		fi

		if ! (sudo ldapsearch -Y EXTERNAL -H ldapi:///  -b 'cn={1}cosine,cn=schema,cn=config' >/dev/null 2>&1 ); then
			if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/cosine.ldif  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "ldapadd cosine.ldif failed. Unable to continue"
				 exitWithFailureCode 71
			fi
		fi
		if ! (sudo ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn={2}nis,cn=schema,cn=config' >/dev/null 2>&1 ); then
			if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/nis.ldif  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "ldapadd nis.ldif failed. Unable to continue"
				 exitWithFailureCode 72
			fi
		fi
		if ! (sudo ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn={3}inetorgperson,cn=schema,cn=config' >/dev/null 2>&1 ); then
			if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f /etc/ldap/schema/inetorgperson.ldif  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "ldapadd inetorgperson.ldif failed. Unable to continue"
				exitWithFailureCode 73
			fi
		fi
		if ! (sudo ldapsearch -Y EXTERNAL -H ldapi:/// -b 'cn=module{0},cn=config' >/dev/null 2>&1 ); then
			if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f ${SCRIPT_DIR}/ldap/backendDBConfig.ldif  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "ldapadd backendDBConfig.ldif failed. Unable to continue"
				exitWithFailureCode 74
			fi
		fi


	else
		log "LDAP database has already been populated."
	fi
		
	log "Copying dataone.schema to ${LDAP_CONF_DIR}/schema/"
	if ! (cp ${SCRIPT_DIR}/ldap/dataone.schema ${LDAP_CONF_DIR}/schema/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy ${SCRIPT_DIR}/ldap/dataone.schema to ${LDAP_CONF_DIR}/schema/"
	fi
	if ! (chown -R ${LDAP_USER}:${LDAP_USER} ${LDAP_CONF_DIR}/schema/dataone.schema >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to chown ${LDAP_CONF_DIR}/schema/dataone.schema"
	fi        
	## place slapd.conf template
	if [ -e ${LDAP_CONF_DIR}/slapd.conf ]; then 
		## if there is a difference, then the diff script returns false
		if ! (diff ${SCRIPT_DIR}/ldap/slapd.conf ${LDAP_CONF_DIR}/slapd.conf); then
			log "Backing up ${LDAP_CONF_DIR}/slapd.conf to ${LDAP_CONF_DIR}/slapd.conf.${LONG_DATE}"
			if ! (mv ${LDAP_CONF_DIR}/slapd.conf ${LDAP_CONF_DIR}/slapd.conf.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to move ${LDAP_CONF_DIR}/slapd.conf to ${LDAP_CONF_DIR}/slapd.conf.${LONG_DATE}"
			fi
		fi
	fi
	
	log "Copying slapd.conf to ${LDAP_CONF_DIR}/"
	if ! (cp ${SCRIPT_DIR}/ldap/slapd.conf ${LDAP_CONF_DIR}/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy ${SCRIPT_DIR}/ldap/slapd.conf to ${LDAP_CONF_DIR}"
	fi
	
	## place ldap.conf template
	if [ -e ${LDAP_CONF_DIR}/ldap.conf ]; then 
		if ! (diff ${SCRIPT_DIR}/ldap/ldap.conf ${LDAP_CONF_DIR}/ldap.conf); then
			log "Backing up ${LDAP_CONF_DIR}/ldap.conf to ${LDAP_CONF_DIR}/ldap.conf.${LONG_DATE}"
			if ! (mv ${LDAP_CONF_DIR}/ldap.conf ${LDAP_CONF_DIR}/ldap.conf.${LONG_DATE} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to Move  ${LDAP_CONF_DIR}/ldap.conf to ${LDAP_CONF_DIR}/ldap.conf.${LONG_DATE}"
			fi
		fi
	fi
	log "Copying ldap.conf to ${LDAP_CONF_DIR}/"
	if ! (cp ${SCRIPT_DIR}/ldap/ldap.conf ${LDAP_CONF_DIR}/ >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to copy${SCRIPT_DIR}/ldap/ldap.conf to ${LDAP_CONF_DIR}"
	fi
	
	# Fetch the DataONE CA
	
	DATAONE_CA_FILEPATH="${SSL_CERT_DIR}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.dataone.ca.filename]}"
	DATAONE_CA_FILEPATH=${DATAONE_CA_FILEPATH//\//\\\/}
		
	## Configure the ldap.conf file with correct value for the CA cert
	if [ -e ${LDAP_CONF_DIR}/ldap.conf ]; then
		if ! (sed -i.bak "s/^\(TLS_CACERT *\).*/\1           ${DATAONE_CA_FILEPATH}/" ${LDAP_CONF_DIR}/ldap.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to modify TLS_CACERT value in ${LDAP_CONF_DIR}/slapd.conf"
		fi            
	fi    
	
	## Configure the slapd.conf file with correct values
	if [ -e ${LDAP_CONF_DIR}/slapd.conf ]; then
		# Fetch the ldap rootpw from the debconf database
		
		## hash the given password when writing to the file
		LDAP_ROOT_PASSWORD=${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.password]}
		LDAP_ROOT_PASSWORD=`slappasswd -n -s ${LDAP_ROOT_PASSWORD}`
		log "using hashed password ${LDAP_ROOT_PASSWORD}"
		
		if ! (sed -i.bak "s/^\(rootpw *\).*/\1           ${LDAP_ROOT_PASSWORD}/" ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to modify rootpw value in ${LDAP_CONF_DIR}/slapd.conf"
		fi            
		# configure the replicaiton certificate fullpath location
		if [ -n "$LDAP_CERTIFICATE" ]; then
			if ! (sed -i.bak "s/^\(TLSCertificateFile *\).*/\1           ${LDAP_CERTIFICATE}/" ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify TLSCACertificateFile value in ${LDAP_CONF_DIR}/slapd.conf"
			fi
			# make sure we have the correct ownership
			if ! (chown ${TOMCAT_USER}:ssl-cert "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.certificate.filename]}">> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to chown ${TOMCAT_USER}:ssl-cert on ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.certificate.filename]}"
			fi
		else
			log "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.certificate.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.certificate.filename]} does not exist. slapd, among other services, will fail"
		fi
		# configure the replication private key fullpath location
		if [ -n "$LDAP_PRIVATEKEY" ]; then         
			if ! (sed -i.bak "s/^\(TLSCertificateKeyFile *\).*/\1           ${LDAP_PRIVATEKEY}/" ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify TLSCertificateKeyFile  value in ${LDAP_CONF_DIR}/slapd.conf"
			fi
			# Set the DataONE CA
			if ! (sed -i.bak "s/^\(TLSCACertificateFile *\).*/\1           ${DATAONE_CA_FILEPATH}/" ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to modify TLSCACertificateFile value in ${LDAP_CONF_DIR}/slapd.conf"
			fi
			
			# make sure we have the correct ownership for the key
			if ! (chown ${TOMCAT_USER}:ssl-cert "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.privatekey.filename]}" >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to chown ${TOMCAT_USER}:ssl-cert on ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.privatekey.filename]}"
			fi
		else
			log "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.client.key.dir]}/${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.replication.privatekey.filename]} does not exist. slapd, among other services, will fail"
		fi
		# Allow us to use non-standard cert/key locations for slapd
		if ! (aa-complain /etc/apparmor.d/usr.sbin.slapd >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "apparmor failed. needs repair."
		fi
		# TODO: instead of disabling apparmor, add exceptions to the config
		# file located here: /etc/apparmor.d/usr.sbin.slapd
		
		
		# Set up sychronization across the listed servers
		#declare -i count
		count=0
		SYNC_SETTINGS="\n"; # synchronization definitions and settings
		if [ "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.synchronized]}" == "true" ]; then
			db_get dataone-cn-os-core/cn.hostnamelist
			local ADDRESSES=${RET}
			db_get dataone-cn-os-core/cn.nodeids
			local NODEIDS=( ${RET} ) # node ids array
			
			for address in ${ADDRESSES}; 
			do
				# only create a replica entry for servers others than this server
				CURRENTNODEID=${NODEIDS[$count]}
				log "Node id in the list is ${CURRENTNODEID}"
				if [ "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.nodeid]}" == "${CURRENTNODEID}" ]; then
					let count=${count}+1
					continue
				else
					let count=${count}+1
					log "Adding LDAP sync config for ${address}"
					SYNC_SETTINGS="${SYNC_SETTINGS}\nsyncRepl rid=${count}"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tprovider=ldap:\/\/${address}:389"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\turi=ldap:\/\/${address}:389"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tbinddn=\"cn=admin,dc=dataone,dc=org\""
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tbindmethod=simple"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tcredentials=${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.password]}"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tsearchbase=\"dc=org\""
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\ttype=refreshAndPersist"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tstarttls=yes"   
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\ttls_cert=${LDAP_CERTIFICATE}"                            
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\ttls_key=${LDAP_PRIVATEKEY}"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\ttls_cacert=${DATAONE_CA_FILEPATH}"                            
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tinterval=00:00:00:05"
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\tretry=\"12 5 300 +\""
					SYNC_SETTINGS="${SYNC_SETTINGS}\n\ttimeout=1"
				fi
			done
				
			SYNC_SETTINGS="${SYNC_SETTINGS}\n\nmirrormode on"
			SYNC_SETTINGS="${SYNC_SETTINGS}\noverlay syncprov"
			SYNC_SETTINGS="${SYNC_SETTINGS}\nsyncprov-checkpoint 50 5"
			SYNC_SETTINGS="${SYNC_SETTINGS}\nsyncprov-sessionlog 100\n"
			
			# Fetch the ldap serverID from the debconf database
			db_get dataone-cn-os-core/cn.openldap.serverID
			SYNC_CONF="${RET}${SYNC_SETTINGS}"
			log ${SYNC_CONF}
			if ! (sed -i.bak "s/^\(serverID *\).*/\1${SYNC_CONF}/" ${LDAP_CONF_DIR}/slapd.conf  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Unable to write replication settings in  ${LDAP_CONF_DIR}/slapd.conf"
			fi
		
		else
			# Fetch the ldap serverID from the debconf database
			db_get dataone-cn-os-core/cn.openldap.serverID
			log "No LDAP replication selected. Setting serverID only."
			if ! (sed -i.bak "s/^\(serverID *\).*/\1           ${RET}/" ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "unable to change the ServerId in ${LDAP_CONF_DIR}/slapd.conf"
			fi
			
		fi
		
	else
		log "Couldn't set LDAP configuration correctly. Configure ${LDAP_CONF_DIR}/slapd.conf manually."
	fi

	
	## set permissions 
	if ! (chown -R ${LDAP_USER}:${LDAP_USER} ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to chown on ${LDAP_CONF_DIR}/slapd.conf"
	fi
	if ! (chown -R ${LDAP_USER}:${LDAP_USER} ${LDAP_CONF_DIR}/ldap.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to chown on ${LDAP_CONF_DIR}/ldap.conf"
	fi
	if ! (chmod 0600 ${LDAP_CONF_DIR}/slapd.conf >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to chmod on ${LDAP_CONF_DIR}/slapd.conf"
	fi        
	# add to ssl-cert group so it can read private keys
	if ! (adduser ${LDAP_USER} ssl-cert >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "unable to add ${LDAP_USER} to group ssl-cert."
	fi
	
	# try to add the dc=org before going through the rest of the routine
	# the worst that could happen is a denied message
	
	
	## stop the default service
	log "Stopping slapd"
	if (pidof slapd  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		if ! (/etc/init.d/slapd stop   >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Unable to stop slapd. Trying SIGARLM"
			if ! (kill -s ALRM `cat /var/run/slapd/slapd.pid`   >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Killing slapd with SIGALRM failed"
				exitWithFailureCode 78
			else
				if (pidof slapd  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "Unable to stop slapd."
					exitWithFailureCode 78	
				fi
			fi
		fi        	
	else
		log "Slapd not running"
	fi
	## start, using slapd.conf file
	log "Generating ldif config using: ${LDAP_CONF_DIR}/slapd.conf"
	
	if [ -e ${LDAP_CONF_DIR}/slapd.d ]; then
	  if ! (rm -rf ${LDAP_CONF_DIR}/slapd.d/* >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		  log "unable to remove files from ${LDAP_CONF_DIR}/slapd.d"
	  fi
	fi
	if ! (slaptest -f ${LDAP_CONF_DIR}/slapd.conf -F ${LDAP_CONF_DIR}/slapd.d >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		log "Unable to process slapd.conf into the ${LDAP_CONF_DIR}/slapd.d. LDAP will not be functional."
		exitWithFailureCode 79
	fi
	#if [ -e "${LDAP_CONF_DIR}/slapd.d/cn=config/olcDatabase={1}hdb.ldif" ]; then
		## NOTE: I see this being broken across a linebreak now with version 2.4.21 (BRL 20120731)
		## http://www.openldap.org/its/index.cgi/Software%20Bugs?id=6465
		## (if i read the bug report correctly it is fixed starting at 2.4.24)
		## the string uri="" finds its way into olcDatabase={1}hdb.ldif file 
		## into the olcSyncrepl directive and breaks OpenLDAP
		## the string uri="" may be found at the beginning of a line, end of a line,
		## middle of the line, or breaking across lines.
		## if it breaks across lines, we need to preserve the newline,
		## and ensure the line afterwards starts with a space.
		## otherwise remove the string, guaranteeing only a single space separates
		## previous setting string to the next setting string 
		#if ! (/usr/bin/perl -pi.bak -e 'BEGIN{undef $/;} s/\hu(\s*)r(\s*)i(\s*)\=(\s*)\"(\s*)\"(\n?)/$1$2$3$4$5$6/mg' ${LDAP_CONF_DIR}/slapd.d/cn=config/olcDatabase={1}hdb.ldif 2>&1 );  then
			#log "perl correction of ${LDAP_CONF_DIR}/slapd.d/cn=config/olcDatabase={1}hdb.ldif failed"
		#fi
		
		#if ! (rm ${LDAP_CONF_DIR}/slapd.d/cn=config/olcDatabase={1}hdb.ldif.bak >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 );  then
			#log "unable to remove ${LDAP_CONF_DIR}/slapd.d/cn=config/olcDatabase={1}hdb.ldif.bak"
		#fi
	#else
		#log "unable to find ${LDAP_CONF_DIR}/slapd.d/cn=config/olcDatabase={1}hdb.ldif"
		#exitWithFailureCode 84
	#fi
	if [ -e /etc/ldap/slapd.d ]; then
	  if ! (chown -R ${LDAP_USER}:${LDAP_USER} /etc/ldap/slapd.d >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 );  then
		  log "chown on /etc/ldap/slapd.d failed"
		  exitWithFailureCode 80
	  fi
	else
		log "/etc/ldap/slapd.d does not exist. Something has gone horribly wrong"
		exitWithFailureCode 80
	fi
	## make sure we own the storage folder
	if [ -e /var/lib/ldap ]; then
	  if ! (chown -R ${LDAP_USER}:${LDAP_USER} /var/lib/ldap >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 );  then
		  log "chown on /var/lib/ldap failed"
	  fi 
	else
	  log "/var/lib/ldap does not exist. Something has gone horribly wrong"
		exitWithFailureCode 81
	fi
	log "Starting slapd"
	LDAP_RUNNING="yes"
	if ! (/etc/init.d/slapd start >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 );  then
		log "Slapd failed to start"
		exitWithFailureCode 91
	fi
	
	sleep 5 # openldap doesn't seem to come up quickly enough
	confirm_ldap_running
	return_val=$?
	if [ "$return_val" -ne "$SUCCESS" ]
	then
		log "Slapd is not running and cannot be restarted. Failure!"
		exitWithFailureCode 92
	fi
	# populate or migrate the LDAP database with the LDIF file for the chosen context
	
	if [ -z "${OPENLDAP_POPULATED}" ] || [ "${OPENLDAP_POPULATED}" == "false" ]; then
		log "This is the first CN to be installed in the environment"
		log "Adding dataone schema specific entries"
		# find out if org.ldif has been added
		if ! (ldapsearch -Y EXTERNAL -H ldapi:///  -b 'dc=org' -s base +  2> /dev/null | grep -q -P '^dn:\sdc=org$'  >/dev/null 2>&1 ); then
			if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f ${SCRIPT_DIR}/ldap/org.ldif >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "ldapadd org.ldif failed. Unable to continue"
				exitWithFailureCode 75
			fi
		fi
		if [ "${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.firstcn]}" == "true" ]; then
			if ! (sudo ldapsearch -Y EXTERNAL -H ldapi:///  -b 'dc=org' -s one 2> /dev/null | grep -q -P '^dn:\sdc=dataone,dc=org$' >/dev/null 2>&1 ); then
				if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f ${SCRIPT_DIR}/ldap/dataone.ldif >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "ldapadd dataone.ldif failed. Unable to continue"
					exitWithFailureCode 76
				fi
			fi
			if ! (sudo ldapsearch -Y EXTERNAL -H ldapi:///  -b 'dc=org' -s one 2> /dev/null | grep -q -P '^dn:\sdc=cilogon,dc=org$' >/dev/null 2>&1 ); then
				if ! (sudo ldapadd -Y EXTERNAL -H ldapi:/// -f ${SCRIPT_DIR}/ldap/cilogon.ldif >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
					log "ldapadd cilogon.ldif failed. Unable to continue"
					exitWithFailureCode 77
				fi
			fi
			if [[ -e "${SCRIPT_DIR}/ldap/${CONTEXT,,}NodeList.ldif" && -n $LDAP_RUNNING ]]; then
			  log "Adding all dataone schema specific entries"
			  if ! (ldapadd -v -c -D cn=admin,dc=dataone,dc=org -w ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.password]} -H ldap://localhost:389 -x -f ${SCRIPT_DIR}/ldap/${CONTEXT,,}NodeList.ldif  >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 ); then
				  log "ldapadd of ${SCRIPT_DIR}/ldap/${CONTEXT,,}NodeList.ldif failed"
			  fi
			else
			  log "${SCRIPT_DIR}/ldap/${CONTEXT,,}NodeList.ldif does not exist or ldap not running- unable to populate ldap for environment ${CONTEXT}"
			fi
		else
			log "Not the first CN in the environment. Skipping LDAP population."
		fi
		db_set dataone-cn-os-core/cn.openldap.populated true
		db_fset dataone-cn-os-core/cn.openldap.populated seen true
	### considering the perl scripts are not used now. comment out the 
	### use of the perl scripts. IF a need arises in the future
	### to modify LDAP because of a migration issue, then the
	### scripts will need to be revisited/refactored
	### https://redmine.dataone.org/issues/6874
#	else
#		if [ -n "$LDAP_RUNNING" ]; then
#		  log "Migrating all dataone schema specific entries"
#		  if ! (${SCRIPT_DIR}/ldap/migrateLdap.pl --version $MIGRATE_VERSION>> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 ); then
#			exitWithFailureCode 82
#		  fi
#		else
#		  log "No migration. Ldap Not running"
#		fi
	fi
	## list the entries
	if [ -n "$LDAP_RUNNING" ]; then
	  log "Listing LDAP Coordinating Node entries for: dc=dataone,dc=org"
	  if ! (ldapsearch -LLL -D cn=admin,dc=dataone,dc=org -w ${DEB_QUESTION_VALUES[dataone-cn-os-core/cn.openldap.password]} -H ldap://localhost:389 -x -b 'dc=dataone,dc=org' 'd1NodeType=cn' >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1 ); then
		  log "ldapsearch for dc=dataone,dc=org failed"
	  fi
	fi
	# Always clear the cached keystore password
	db_set dataone-cn-os-core/cn.openldap.password "" # clear the cached pw
	db_fset dataone-cn-os-core/cn.openldap.password seen false
	eval local -a DEB_FLAG_BOOLEAN=("${DEB_QUESTION_FLAGS[dataone-cn-os-core/cn.openldap.password]}")
	DEB_FLAG_BOOLEAN[$SEEN]="false"
	unset -v DEB_QUESTION_FLAGS[dataone-cn-os-core/cn.openldap.password]
	DEB_QUESTION_FLAGS+=([dataone-cn-os-core/cn.openldap.password]="${DEB_FLAG_BOOLEAN[@]}")
	## done with OpenLDAP
	log "LDAP configuration complete"
	
	sleep 5

}

#####
##### configure_bouncycastle()
##### install the bouncycastle jars into the java security ext directory
##### and modify the java security properties file to allow bouncycastle
##### to handle auth
#####
function configure_bouncycastle()
{
	###############################################################################
	# Configure BouncyCastle for Java Security (before starting tomcat)
	###############################################################################
	## XXX   XXX   XXX   -RPW Do we still need bouncy castle as a jce provider for our installation to work?
	## 2015-03-18 BRL: remove bouncycastle jars on install and require individual projects to manage that dependency
	
	if ! (grep -q -P '=org\.bouncycastle\.jce\.provider\.BouncyCastleProvider' ${JAVA_SECURITY}); then
		echo "bouncycastle security provider NOT previously installed"
	else
		echo "bouncycastle security provider previously installed"
		## TODO: remove BC provider entry from java.security?
	fi
	
	if [ -e ${JAVA_SECURITY_EXT_DIR}/bcprov-*.jar ]; then
		echo "we need to remove the bcprov-*.jar file"	
		if ! (rm ${JAVA_SECURITY_EXT_DIR}/bcprov-*.jar >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Removing ${JAVA_SECURITY_EXT_DIR}/bcprov-*.jar failed"
		fi
		#if ! (cp ${SOURCE_DIR}/bcprov-jdk15on-1.46.jar ${JAVA_SECURITY_EXT_DIR} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
		#	log "Copy of ${SOURCE_DIR}/bcprov-jdk15on-1.46.jar to ${JAVA_SECURITY_EXT_DIR} failed"
		#fi
		
	fi
	if [ -e ${JAVA_SECURITY_EXT_DIR}/bcmail-*.jar ]; then
		echo "we need to remove the bcmail-*.jar file"		
		if ! (rm ${JAVA_SECURITY_EXT_DIR}/bcmail-*.jar >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "Removing ${JAVA_SECURITY_EXT_DIR}/bcmail-*.jar failed"
		fi
		
	fi
	
}


#####
##### configure_ssl()
##### In order to accomodate the certificates signed by DataONE CA, we need to modify the ssl
#####
function configure_ssl()
{
    log "update ssl settings to support the DataONE CA"
    sed -i.bak 's/DEFAULT:@SECLEVEL=2/DEFAULT:@SECLEVEL=0/' /etc/ssl/openssl.cnf
}



#####
##### configure_check_mk()
##### make certain check_mk exists and has correct permissions
#####
function configure_check_mk()
{
	###############################################################################
	# Configure check_mk
	###############################################################################
	if [ -e /usr/lib/check_mk_agent ]; then
		if ! (chown -R root:root /usr/lib/check_mk_agent >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "failed to chown -R root:root /usr/lib/check_mk_agent"
		fi
		if ! (chmod -R 755 /usr/lib/check_mk_agent >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
			log "failed to chmod -R 755 /usr/lib/check_mk_agent"
		fi
	else
		log "check_mk_agent is missing. Something has gone horribly wrong"
		exitWithFailureCode 83
	fi
	######################################
	
	
}
#####
##### debug_xml_template_flags()
##### log a bunch of settings from the XML_TEMPLATE_FLAGS datastructure
#####
function debug_xml_template_flags()
{
	local template_name
	log "XML_TEMPLATE_FLAGS\t SEEN \t DERIVED_VALUE \t CONFIGURED_VALUE \t USER_ENTERED_VALUE"
	for template_name in ${!XML_TEMPLATE_FLAGS[@]}
	do
		eval declare -a XML_TEMPLATE_BOOLEAN=("${XML_TEMPLATE_FLAGS[$template_name]}")
		log "$template_name\t${XML_TEMPLATE_BOOLEAN[$SEEN]}\t${XML_TEMPLATE_BOOLEAN[$DERIVED_VALUE]}\t${XML_TEMPLATE_BOOLEAN[$CONFIGURED_VALUE]}\t${XML_TEMPLATE_BOOLEAN[$USER_ENTERED_VALUE]}"
	done
}
#####
##### debug_xml_question_values()
##### log a bunch of settings from the XML_QUESTION_VALUES datastructure
#####
function debug_xml_question_values()
{
	local template_name
	log "XML_QUESTIONS \t VALUES"
	for template_name in ${!XML_QUESTION_VALUES[@]}
	do
		if ! [[ $template_name =~ ^.*password.*$ ]]; then
			log "$template_name \t ${XML_QUESTION_VALUES[$template_name]}"
		fi
	done
}
#####
##### debug_deb_question_flags()
##### log a bunch of settings from the DEB_QUESTION_FLAGS datastructure
#####
function debug_deb_question_flags()
{
	log "DEB_QUESTION_FLAGS\t SEEN \t DERIVED_VALUE \t CONFIGURED_VALUE \t USER_ENTERED_VALUE"
	for template_name in ${!DEB_QUESTION_FLAGS[@]}
	do
		eval declare -a DEB_QUESTION_BOOLEAN=("${DEB_QUESTION_FLAGS[$template_name]}")
		log "$template_name\t${DEB_QUESTION_BOOLEAN[$SEEN]}\t${DEB_QUESTION_BOOLEAN[$DERIVED_VALUE]}\t${DEB_QUESTION_BOOLEAN[$CONFIGURED_VALUE]}\t${DEB_QUESTION_BOOLEAN[$USER_ENTERED_VALUE]}"
	done
}
#####
##### debug_deb_question_values()
##### log a bunch of settings from the DEB_QUESTION_VALUES datastructure
#####
function debug_deb_question_values()
{
	local template_name
	log "DEB_QUESTION \t VALUES"
	for template_name in ${!DEB_QUESTION_VALUES[@]}
	do
		if ! [[ $template_name =~ ^.*password.*$ ]]; then
			log "$template_name \t ${DEB_QUESTION_VALUES[$template_name]}"
		fi
	done
}
#####
##### main()
##### simulate a main function
#####
function main()
{
	log "dataone-cn-os-core.postinst called  with action: ${ACTION} and version: ${ARG_VERSION}"

	case "${ACTION}" in
		abort-remove)
		log "Removal aborted."
		;;
		abort-upgrade)
		log "Upgrade aborted."
		;;
		abort-deconfigure)
		log "Deconfigure aborted."
		;;
		configure)
		log "Configure called."


		if [ -z "$ARG_VERSION" ]; then
		  FIRSTINST="yes"
		else 
		  UPGRADE="yes"
		fi

		download_validate_config_xml
		build_xml_template_data_structures
		build_debianDB_template_data_structures

		debug_xml_question_values
		debug_xml_template_flags
		if [ -n "$DEBCONF_RECONFIGURE" ]; then
			log "MUST RECONFIGURE!!!"
			RECONFIGURE="yes"
		fi

		if (/usr/bin/dpkg --compare-versions "${ARG_VERSION}" lt 1.2.1); then
			RECONFIGURE="yes"
		fi

		if [[ "$FIRSTINST" == "yes"  || "$RECONFIGURE" == "yes" ]]; then
			##################################################################
			# Set the context of the deployment (LOCALHOST, DEV, STAGE, SANDBOX, PRODUCTION)
			##################################################################
			# Fetch the cn.context.label from the debconf database and set the per-environment variables
			log "First Installation"
			process_create_debian_config

			debug_deb_question_values
			debug_deb_question_flags

			configure_certificates

			configure_node_properties_file

			configure_ufw
			
			configure_jdk

			configure_keystore

			configure_apache

			configure_tomcat

			configure_openldap

			configure_bouncycastle
			
			configure_ssl

			log "ETC configuration"                 
			###############################################################################
			# Start Tomcat
			###############################################################################
			log "starting Tomcat server"

			if ! (systemctl start ${TOMCAT} >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "Tomcat server failed to start"
			fi
			if ! (cp ${SOURCE_DIR}/d1_cn_approve_node.jar /usr/share/java >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
				log "failed to copy ${SOURCE_DIR}/d1_cn_approve_node.jar to /usr/share/java"
			fi
			chmod 700 /usr/share/java/d1_cn_approve_node.jar
			chmod 700 /usr/local/bin/dataone-approve-node
			log "Configuration of dataone-cn-os-core complete."
		else
			## does not appear that update will have to touch tomcat
			# if tomcat is re-installed and the configuration files
			# deleted, or otherwise corrupted, then 
			# this package will need to be reconfigured

			log "Update the configuration."
			process_update_debian_config
			debug_deb_question_values
			debug_deb_question_flags

			# if any of the following template questions change
			# then reconfigure the certificates
			# dataone-cn-os-core/cn.client.key.dir
			# dataone-cn-os-core/cn.client.certificate.filename
			# dataone-cn-os-core/cn.server.privatekey.filename
			# dataone-cn-os-core/cn.server.publiccert.filename
			# dataone-cn-os-core/cn.client.certificate.dir
			if [[ "${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.client.key.dir]}" == "true" ||
				"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.client.certificate.filename]}" == "true" ||
				"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.server.privatekey.filename]}" == "true" ||
				"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.server.publiccert.filename]}" == "true" ||
				"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.client.certificate.dir]}" == "true" ]];then
				configure_certificates
			fi
			# if any of the following template questions change
			# then reconfigure the node properties file
			# dataone-cn-os-core/cn.context.label
			# dataone-cn-os-core/cn.iplist
			# dataone-cn-os-core/cn.nodeids
			# dataone-cn-os-core/cn.nodeid
			# dataone-cn-os-core/cn.router.nodeId
			# dataone-cn-os-core/cn.router.hostname
			# dataone-cn-os-core/cn.client.certificate.filename
			# dataone-cn-os-core/cn.hostname
			# if [[ "${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.context.label]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.iplist]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.nodeids]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.nodeid]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.router.nodeId]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.router.hostname]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.client.certificate.filename]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.hostname]}" == "true" ]];then
			#	configure_node_properties_file
			# fi
			# the node properties file is always overwritten, so we have to configure it without conditions
			configure_node_properties_file
			
			# if the following template question changes
			# then reconfigure ufw
			# dataone-cn-os-core/cn.iplist
			configure_jdk
			if [[ "${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.iplist]}" == "true" ]]; then
				configure_ufw
			fi

			# if the following template question changes
			# then reconfigure the keystore
			# dataone-cn-os-core/cn.dataone.ca.filename
			#if [[ "${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.dataone.ca.filename]}" == "true" ]]; then
				configure_keystore
			#fi
			# if the following template questions change
			# then reconfigure apache
			# dataone-cn-os-core/cn.hostname
			# dataone-cn-os-core/cn.dataone.ca.filename
			# dataone-cn-os-core/cn.server.publiccert.filename
			# dataone-cn-os-core/cn.server.privatekey.filename
			# if [[ "${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.hostname]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.dataone.ca.filename]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.server.publiccert.filename]}" == "true" ||
			#	"${DB_QUESTION_CHANGED[dataone-cn-os-core/cn.server.privatekey.filename]}" == "true" ]];then
			#	configure_apache
			#fi
			
			# XXX reconfigure apache and tomcat until add in better logic to determine when static files have changed
			configure_apache
			configure_tomcat
			# due to the fact that we do not know if the password has been changed
			# we will always have to reconfigure openldap until
			# the logic surrounding passwords change
			configure_openldap
			#reconfigure the bouncycastle if it is ncessary.
			configure_bouncycastle
		fi
		

			
		#####
		#### postinst needs to determine if ansible is controlling the install/upgrade
		#### need to communicate between ansible and debian about the state of the installation
		#### if ansible is run to upgrade, then the next time postinst runs
		#### the seen flag will be true, and we accept all of ansible's values
		#### however if seen is false, then we assume that debian is 
		#### running alone and should determine how to update the 
		#### template values
		#### then postinst will assume that ansible is not controlling the install
		#### always do this as the last method to call for either
		#### install/reconfigure or update
		resetDebQuestionSeenFlag
		;;
	esac
	
	db_stop
	exit 0
}

#### This is the start of all the processing!!!
if (debconf-show dataone-cn-os-core >> ${D1_LOG_DIR}/${D1_LOG_FILE} 2>&1); then
	log "before main"
fi
main
################ NOTHING SHOULD APPEAR BELOW THIS LINE ################
