#!/bin/sh
#
# Copyright (C) 1994-2021 Altair Engineering, Inc.
# For more information, contact Altair at www.altair.com.
#
# This file is part of both the OpenPBS software ("OpenPBS")
# and the PBS Professional ("PBS Pro") software.
#
# Open Source License Information:
#
# OpenPBS is free software. You can redistribute it and/or modify it under
# the terms of the GNU Affero General Public License as published by the
# Free Software Foundation, either version 3 of the License, or (at your
# option) any later version.
#
# OpenPBS is distributed in the hope that it will be useful, but WITHOUT
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public
# License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# Commercial License Information:
#
# PBS Pro is commercially licensed software that shares a common core with
# the OpenPBS software.  For a copy of the commercial license terms and
# conditions, go to: (http://www.pbspro.com/agreement.html) or contact the
# Altair Legal Department.
#
# Altair's dual-license business model allows companies, individuals, and
# organizations to create proprietary derivative works of OpenPBS and
# distribute them - whether embedded or bundled with other software -
# under a commercial license agreement.
#
# Use of Altair's trademarks, including but not limited to "PBS™",
# "OpenPBS®", "PBS Professional®", and "PBS Pro™" and Altair's logos is
# subject to Altair's trademark licensing policies.


if [ $# -eq 1 -a "$1" = "--version" ]; then
   echo pbs_version = 23.06.06
   exit 0
fi

PBS_VERSION=23.06.06
INSTALL_DB="install_db"
UPGRADE_DB="upgrade_db"

get_db_user() {
	[ -f "${dbuser_fl}" ] && dbuser_name=`cat "${dbuser_fl}" | tr -d '[:space:]'`
	[ -z "${dbuser_name}" ] && dbuser_name="${PBS_DATA_SERVICE_USER:-postgres}"
	if [ ! -f "${dbuser_fl}" ]; then
		printf "%s" "$dbuser_name" >"${dbuser_fl}"
		chmod 0600 "${dbuser_fl}"
	fi
	cat "${dbuser_fl}"
	return $?
}

chk_dataservice_user() {
	chk_usr="$1"

	# do user-id related stuff first
	id=`id ${chk_usr} 2>&1`
	if [ $? -ne 0 ]; then
		echo "PBS Data Service user ${chk_usr} does not exist"
		return 1;
	fi

	id=`echo ${id} | cut -c5- | cut -d "(" -f1`
	if [ "$id" = "0" ]; then
		echo "User ${chk_usr} should not have root privileges"
		return 1;
	fi

	# login as ${chk_usr} and try to cd to user home dir
	su - ${chk_usr} -c "cd" > /dev/null 2>&1

	if [ $? -ne 0 ]; then
		echo "Unable to login as user ${chk_usr}. Is the user enabled/home directory accessible?"
		return 1
	fi
	return 0
}

is_cray_xt() {
	if [ -f /proc/cray_xt/cname ] ; then
		return 0
	fi
	return 1
}

chkenv() {
	line=`grep -s "^${1}=" $envfile`
	if [ -z "$line" ]; then
		echo "*** setting ${1}=$2"
		echo "${1}=$2" >> $envfile
	else
		echo "*** leave existing $line"
	fi
}

createdir() {
	if [ -n "$1" -a ! -d "$1" ]; then
		if ! mkdir -p "$1"; then
			echo "*** Could not create $1"
			exit 1
		fi
	fi
	if [ -n "$1" -a -n "$2" ]; then
		chmod "$2" "$1"
	fi
}

createpath() {
	while read mode dir ;do
		createdir "${PBS_HOME}/${dir}" $mode
	done
}

# Return the name of the PBS server host
get_server_hostname() {
	shn=""
	if [ -z "${PBS_PRIMARY}" -o -z "${PBS_SECONDARY}" ] ; then
		if [ -z "${PBS_SERVER_HOST_NAME}" ]; then
			shn="${PBS_SERVER}"
		else
			shn="${PBS_SERVER_HOST_NAME}"
		fi
	else
		shn="${PBS_PRIMARY}"
	fi
	echo ${shn} | awk '{print tolower($0)}'
}

# Ensure the supplied hostname is valid
check_hostname() {
	# Check the hosts file
	getent hosts "${1}" >/dev/null 2>&1 && return 0
	# Check DNS
	host "${1}" >/dev/null 2>&1 && return 0
	return 1
}

# Backup pgsql binaries and libraries to PBS_EXEC
backup_pgsql() {
	psql_ver=`psql --version | cut -d ' ' -f3 | cut -d '.' -f 1,2`
	mkdir -p "$PBS_HOME/pgsql.forupgrade/bin"
	mkdir -p "$PBS_HOME/pgsql.forupgrade/lib"
	mkdir -p "$PBS_HOME/pgsql.forupgrade/lib64/pgsql"
	mkdir -p "$PBS_HOME/pgsql.forupgrade/share/pgsql/timezonesets"
	mkdir -p "$PBS_HOME/pgsql.forupgrade/share/timezonesets"
	pgsql_lib_dir=`dirname $PGSQL_BIN`"/lib64/pgsql"
	if [ ! -d $pgsql_lib_dir ];then
		pgsql_lib_dir="/usr/pgsql-${psql_ver}/lib"
	fi
	cp -r $pgsql_lib_dir/* "$PBS_HOME/pgsql.forupgrade/lib64/pgsql"
	cp -r $pgsql_lib_dir/* "$PBS_HOME/pgsql.forupgrade/lib/"
	pgsql_share_dir=`dirname $PGSQL_BIN`"/share/pgsql"
	if [ ! -d $pgsql_share_dir ];then
		pgsql_share_dir="/usr/pgsql-${psql_ver}/share"
	fi
	cp -r $pgsql_share_dir/timezonesets/* "$PBS_HOME/pgsql.forupgrade/share/pgsql/timezonesets"
	cp -r $pgsql_share_dir/timezonesets/* "$PBS_HOME/pgsql.forupgrade/share/timezonesets"
	cp "$PGSQL_BIN/pg_ctl" "$PBS_HOME/pgsql.forupgrade/bin"
	cp "$PGSQL_BIN/postgres" "$PBS_HOME/pgsql.forupgrade/bin"
	cp "$PGSQL_BIN/pg_controldata" "$PBS_HOME/pgsql.forupgrade/bin"
	cp "$PGSQL_BIN/pg_resetxlog" "$PBS_HOME/pgsql.forupgrade/bin"
	cp "$PGSQL_BIN/psql" "$PBS_HOME/pgsql.forupgrade/bin"
	cp "$PGSQL_BIN/pg_dump" "$PBS_HOME/pgsql.forupgrade/bin"
	cp "$PGSQL_BIN/pg_restore" "$PBS_HOME/pgsql.forupgrade/bin"
	psql_ver_min=9.3
	if [ ${psql_ver_min%.*} -eq ${psql_ver%.*} ] && [ ${psql_ver_min#*.} \> ${psql_ver#*.} ] || [ ${psql_ver_min%.*} -gt ${psql_ver%.*} ]; then
		touch "$PBS_HOME/pgsql.forupgrade/oss"
	fi
}

#
# Start of the pbs_habitat script
#
conf=${PBS_CONF_FILE:-/etc/pbs.conf}
ostype=`uname 2>/dev/null`
umask 022

echo "***"

# Source pbs.conf to get paths: PBS_EXEC and PBS_HOME and PBS_START_*
. $conf

# Ensure certain variables are set
if [ -z "$PBS_EXEC" ]; then
	echo "*** PBS_EXEC is not set"
	exit 1
fi
if [ ! -d "$PBS_EXEC" ]; then
	echo "*** $PBS_EXEC directory does not exist"
	exit 1
fi
if [ -z "$PBS_HOME" ]; then
	echo "*** PBS_HOME is not set"
	exit 1
fi
if [ ! -d "$PBS_HOME" -o ! "$(/bin/ls -A $PBS_HOME)" ]; then
	echo "*** WARNING: PBS_HOME not found in $PBS_HOME"
	if [ -x "$PBS_EXEC/sbin/pbs_server" ]; then
		component="server"
	elif [ -x "$PBS_EXEC/sbin/pbs_mom" ]; then
		component="execution"
	else
		echo "*** No need to execute pbs_habitat in client installation."
		exit 0
	fi
	${PBS_EXEC}/libexec/pbs_postinstall $component $PBS_VERSION $PBS_EXEC $PBS_HOME "" "sameconf"
fi


# Get the current PBS version from qstat
if [ -x "$PBS_EXEC/bin/qstat" ]; then
	pbs_version=`"${PBS_EXEC}/bin/qstat" --version | sed -e 's/^.* = //'`
	if [ -z "$pbs_version" ]; then
		echo "*** Could not obtain PBS version from qstat"
		exit 1
	fi
	if [ "$pbs_version" != "$PBS_VERSION" ]; then
		echo "*** Version mismatch."
		echo "*** Build version is $PBS_VERSION"
		echo "*** qstat version is $pbs_version"
		exit 1
	fi
else
	echo "*** File not found: $PBS_EXEC/bin/qstat"
	exit 1
fi

# Perform sanity check on server name in pbs.conf
server_hostname=`get_server_hostname`
[ "$server_hostname" = 'change_this_to_pbs_server_hostname' ] && server_hostname=''
if [ -z "${server_hostname}" ] ; then
	echo "***" >&2
	echo "*** The hostname of the PBS server in ${conf} is invalid." >&2
	echo "*** Update the configuration file before starting PBS." >&2
	echo "***" >&2
	exit 1
fi
check_hostname "${server_hostname}"
if [ $? -ne 0 ]; then
	echo "***" >&2
	echo "*** The PBS server could not be found: $server_hostname" >&2
	echo "*** This value must resolve to a valid IP address." >&2
	echo "***" >&2
	exit 1
fi
server=`echo ${server_hostname} | awk -F. '{print $1}'`

if [ "${PBS_START_SERVER:-0}" != 0 ] ; then
	# Check for the db install script
	if [ ! -x "${PBS_EXEC}/libexec/pbs_db_utility" ]; then
		echo "${PBS_EXEC}/libexec/pbs_db_utility not found"
		exit 1
	fi

	# Source the file that sets DB env variables
	. "$PBS_EXEC"/libexec/pbs_db_env
	if [ $? -ne 0 ]; then
		echo "Could not setup PBS Data Service environment"
		exit 1
	fi

	PBS_licensing_loc_file=PBS_licensing_loc

	dbuser_fl="${PBS_HOME}/server_priv/db_user"
	PBS_DATA_SERVICE_USER=`get_db_user`
	if [ $? -ne 0 ]; then
		echo "Could not retrieve PBS Data Service User"
		exit 1
	fi

	# Do not export the PBS_DATA_SERVICE_USER as a env var
	# since that would cause a false warning message
	# that "deprecated" variable PBS_DATA_SERVICE_USER is
	# being ignored.

	chk_dataservice_user ${PBS_DATA_SERVICE_USER}
	if [ $? -ne 0 ]; then
		exit 1
	fi
	export PBS_DATA_SERVICE_USER

	server_started=0
	PBS_DATA_SERVICE_PORT=${PBS_DATA_SERVICE_PORT:-"15007"}
	export PBS_DATA_SERVICE_PORT

	create_new_svr_data=1

	# invoke the dataservice creation script for pbs
	resp=`${PBS_EXEC}/libexec/pbs_db_utility ${INSTALL_DB} 2>&1`
	ret=$?
	if [ $ret -eq 2 ]; then
		create_new_svr_data=0
	elif [ $ret -ne 0 ]; then
		echo "*** Error initializing the PBS dataservice"
		echo "Error details:"
		echo "$resp"
		exit $ret
	fi

	export PBS_HOME
	export PBS_EXEC
	export PBS_SERVER
	export PBS_ENVIRONMENT

	if [ $create_new_svr_data -eq 0 ]; then
		# datastore directory already exists
		# do the database upgrade
		${PBS_EXEC}/libexec/pbs_db_utility ${UPGRADE_DB}
	fi

	if [ $create_new_svr_data -eq 1 ] ; then
		echo "*** Setting default queue and resource limits."
		echo "***"

		${PBS_EXEC}/sbin/pbs_server -t create > /dev/null
		ret=$?
		if [ $ret -ne 0 ]; then
			echo "*** Error starting pbs server"
			exit $ret
		fi
		server_started=1

		if is_cray_xt; then
			${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
				set server restrict_res_to_release_on_suspend = ncpus
			EOF
		fi
		tries=3
		while [ $tries -ge 0 ]
		do
			${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
				create queue workq
			EOF
			ret=$?
			if [ $ret -eq 0 ]; then
				break
			fi
			tries=$((tries-1))
			sleep 2
		done
		${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
			set queue workq queue_type = Execution
			set queue workq enabled = True
			set queue workq started = True
			set server default_queue = workq
		EOF
		if [ -f ${PBS_HOME}/server_priv/$PBS_licensing_loc_file ]; then
			read ans < ${PBS_HOME}/server_priv/$PBS_licensing_loc_file
			echo "*** Setting license file location(s)."
			echo "***"
			${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
				set server pbs_license_info = $ans
			EOF
			if ! is_cray_xt; then
				rm -f ${PBS_HOME}/server_priv/$PBS_licensing_loc_file	# clean up after INSTALL
			fi
		fi
	else
		# the upgrade case:  serverdb already exists, but license file
		# information is new
		if [ -f ${PBS_HOME}/server_priv/$PBS_licensing_loc_file ]; then
			read ans < ${PBS_HOME}/server_priv/$PBS_licensing_loc_file
			echo "*** Setting license file location(s)."
			echo "***"
			${PBS_EXEC}/sbin/pbs_server > /dev/null
			${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
				set server pbs_license_info = $ans
			EOF
			if ! is_cray_xt; then
				rm -f ${PBS_HOME}/server_priv/$PBS_licensing_loc_file	# clean up after INSTALL
			else
				${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
					set server restrict_res_to_release_on_suspend += ncpus
				EOF
			fi
			server_started=1
		fi
	fi

	if [ $PBS_START_MOM != 0 ]; then
		if [ $server_started -eq 0 ]; then
			${PBS_EXEC}/sbin/pbs_server > /dev/null
			server_started=1
		fi

		if ${PBS_EXEC}/bin/pbsnodes localhost > /dev/null 2>&1 ||
		   ${PBS_EXEC}/bin/pbsnodes $server > /dev/null 2>&1; then
			:
		else
			# node $server is not already available, create
			${PBS_EXEC}/bin/qmgr <<-EOF > /dev/null
				create node $server
			EOF
		fi
	fi

	if [ $server_started -eq 1 ]; then
		${PBS_EXEC}/bin/qterm
	fi

	# Take a backup of pgsql binaries and lib to the PBS_EXEC folder
	backup_pgsql

fi

#
# For overlay upgrades PBS_START_MOM will be disabled per the install
# instructions. There may still be job and task files present that
# require updating.
#
if [ -d ${PBS_HOME}/mom_priv/jobs ]; then
	upgrade_cmd="${PBS_EXEC}/sbin/pbs_upgrade_job"
	if [ -x ${upgrade_cmd} ]; then
		total=0
		upgraded=0
		for file in ${PBS_HOME}/mom_priv/jobs/*.JB; do
			if [ -f ${file} ]; then
				${upgrade_cmd} -f ${file}
				if [ $? -ne 0 ]; then
					echo "Failed to upgrade ${file}"
				else
					upgraded=`expr ${upgraded} + 1`
				fi
				total=`expr ${total} + 1`
			fi
		done
		if [ ${total} -gt 0 ]; then
			echo "Upgraded ${upgraded} of ${total} job files."
		fi
	else
		echo "WARNING: $upgrade_cmd not found!"
	fi
fi

# Update the version file at the very end, after everything else succeeds.
# This allows it to be re-run, in case a previous update attempt failed.
# Clobber the existing pbs_version file and populate it with current version.
# This will prevent updating PBS_HOME if this same version is re-installed
#
echo "${pbs_version}" >"$PBS_HOME/pbs_version"

echo "*** End of ${0}"
exit 0
