#!/usr/bin/bash

# Define logging functions
send_systemd_notify() {
    # return if no systemd-notify found
    type systemd-notify >/dev/null 2>&1 || return
    systemd-notify "$@"
}

log_failure_msg() {
    send_systemd_notify --status "Error: $@"
    echo $@
}

# Create bdii config for the NorduGrid/ARC information system

ARC_LOCATION=${ARC_LOCATION:-/usr}
if [ ! -d "$ARC_LOCATION" ]; then
    log_failure_msg "ARC_LOCATION ($ARC_LOCATION) not found"
    exit 1
fi

# ARC_CONFIG
if [ "x$ARC_CONFIG" = "x" ]; then
    if [ -r $ARC_LOCATION/etc/arc.conf ]; then
        ARC_CONFIG=$ARC_LOCATION/etc/arc.conf
    elif [ -r /etc/arc.conf ]; then
        ARC_CONFIG=/etc/arc.conf
    fi
    if [ ! -r "$ARC_CONFIG" ]; then
        log_failure_msg "arc.conf is missing at path: $ARC_CONFIG or no ARC_LOCATION is set"
        log_failure_msg "If this file is in a non-standard place it can be set"
        log_failure_msg "  with the ARC_CONFIG environment variable"
        exit 1
    fi
fi

# Define runtime config location for infosys LDAP
prefix=/usr
runtime_config_dir=/run/arc
if [ ! -d "$runtime_config_dir" ]; then
    mkdir -p "$runtime_config_dir"
fi
export ARC_RUNCONFIG="$runtime_config_dir/arc-infosys-ldap.conf"
unset runtime_config_dir
unset prefix

# Define arcconfig-parser and dump running configuration
arcconfig_parser=${ARC_LOCATION}/libexec/arc/arcconfig-parser
${arcconfig_parser} -c ${ARC_CONFIG} --save -r ${ARC_RUNCONFIG}

# Check for infosys block
if ! ${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys; then
    log_failure_msg "Missing [infosys] configuration block"
    exit 1
fi

# Check for infosys/ldap block
if ! ${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys/ldap; then
    log_failure_msg "Missing [infosys/ldap] configuration block"
    exit 1
fi

eval $(${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys/ldap -b infosys -b common -e bash)

bdii_user=$CONFIG_user
if [ -z "$bdii_user" ]; then
    # Get ldap user from passwd
    bdii_user=`getent passwd ldap openldap | sed 's/:.*//;q'`
    if [ -z "$bdii_user" ]; then
	echo "Warning, could not find ldap or openldap user"
	echo "resorting to using the root user"
	bdii_user=root
    fi
fi

# These values may be set in arc.conf, otherwise use sensible defaults
providerlog=${CONFIG_logfile:-/var/log/arc/infoprovider.log}

bdii_location=${CONFIG_bdii_location:-/usr}
bdii_update_cmd=${CONFIG_bdii_update_cmd:-${bdii_location}/sbin/bdii-update}
if [ ! -x $bdii_update_cmd ]; then
    log_failure_msg "Can not find bdii-update command at: $bdii_update_cmd."
    echo "Please set bdii_update_cmd in arc.conf"
    exit 1
fi

infosys_ldap_run_dir=${CONFIG_infosys_ldap_run_dir:-/run/arc/infosys}
mkdir -p ${infosys_ldap_run_dir}
chown ${bdii_user}: ${infosys_ldap_run_dir}

# Put BDII update helper to known directory
helpers_dir=$infosys_ldap_run_dir
if [ -n "$FORCE_ARC_RUNDIR" ]; then
    helpers_dir="${FORCE_ARC_RUNDIR}/infosys"
    mkdir -p "${helpers_dir}"
fi

bdii_update_exechelper_cmd=${helpers_dir}/bdii-update.cmd
rm -f $bdii_update_exechelper_cmd
bdii_update_posthelper_cmd=${helpers_dir}/bdii-update-post.cmd
rm -f $bdii_update_posthelper_cmd

bdii_debug_level=${CONFIG_bdii_debug_level:-WARNING}

bdii_tmp_dir=${CONFIG_bdii_tmp_dir:-/var/tmp/arc/bdii}
bdii_var_dir=${CONFIG_bdii_var_dir:-/var/lib/arc/bdii}
bdii_run_dir=${CONFIG_bdii_run_dir:-/run/arc/bdii}
bdii_log_dir=${CONFIG_bdii_log_dir:-/var/log/arc/bdii}
bdii_log_file="${bdii_log_dir}/bdii-update.log"

bdii_slapd_conf=${infosys_ldap_run_dir}/bdii-slapd.conf

bdii_default_ldif=${bdii_tmp_dir}/provider/arc-default.ldif.pl
bdii_ldif_dir=${bdii_tmp_dir}/ldif
bdii_provider_dir=${bdii_tmp_dir}/provider
bdii_plugin_dir=${bdii_tmp_dir}/plugin

bdii_port=${CONFIG_port:-2135}

# Using uppercase characters in bdii_bind will break infosys.
bdii_bind="o=grid"

# $bdii_provider_timeout refers to the time bdii waits for the provider output to complete.
bdii_provider_timeout=${CONFIG_bdii_provider_timeout:-10800}
# $infoproviders_timelimit is a-rex's infoproviders timeout.
infoproviders_timelimit=$(${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b arex -o infoproviders_timelimit)
infoproviders_timelimit=${infoproviders_timelimit:-10800}
# $wakeupperiod is the time a-rex waits before running infoproviders again.
wakeupperiod=$(${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b arex -o wakeupperiod)
wakeupperiod=${wakeupperiod:-120}
bdii_archive_size=${CONFIG_bdii_archive_size:-0}

# The infoprovider does the waiting, no need for BDII to do it too.  Use
# some small timeout to protect the system in case there is a problem with
# the provier
bdii_breathe_time=${CONFIG_bdii_breathe_time:-10}

# max_cycle is the time bdii will trust the content of any provider to be fresh enough
max_cycle=$(( $bdii_provider_timeout + $infoproviders_timelimit + $wakeupperiod ))
bdii_read_timeout=${CONFIG_bdii_read_timeout:-$max_cycle}

bdii_delete_delay=${CONFIG_bdii_delete_delay:-0}

# PIDFile location handling
update_pid_file=$( readlink -m ${CONFIG_bdii_update_pid_file:-$bdii_run_dir/bdii-update.pid} )

# forced pidfile location instead of arc.conf-based (if FORCE_ARC_RUNDIR is set)
if [ -n "$FORCE_ARC_RUNDIR" ]; then
    pid_dir="${FORCE_ARC_RUNDIR}/bdii"
    mkdir -p "$pid_dir"
    chown -R ${bdii_user}: "$pid_dir"
    pid_file="$( readlink -m ${pid_dir}/bdii-update.pid )"
    if [ "x${update_pid_file}" != "x${pid_file}" ]; then
        custom_pid_file="${update_pid_file}"
        rm -f "${custom_pid_file}"
        update_pid_file="${pid_file}"
    fi
    unset pid_dir pid_file
fi

rm -f "${update_pid_file}"

# Debian does not have /run/lock/subsys
if [ -d /run/lock/subsys ]; then
    update_lock_file=${update_lock_file:-/run/lock/subsys/arc-bdii-update}
else
    update_lock_file=${update_lock_file:-/run/lock/arc-bdii-update}
fi

# Check directories and permissions
mkdir -p `dirname $providerlog`
touch ${providerlog}
chown ${bdii_user}: ${providerlog}

mkdir -p $bdii_log_dir
chown -R ${bdii_user}: ${bdii_log_dir}

if ${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys/nordugrid || \
   ${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys/glue2/ldap; then
   if [ ! -f "$ARC_LOCATION/share/arc/InfosysHelper.pm" ]; then
	  log_failure_msg "InfosysHelper.pm not found. Is A-REX installed?"
	  echo "For operation without A-REX, disable publishing of cluster information"
	  echo "([infosys/nordugrid] and [infosys/glue2/ldap])"
	  exit 1
   fi
fi

BDII_CONF=${CONFIG_bdii_conf:-${infosys_ldap_run_dir}/bdii.conf}

# Create directories for storing temporary scripts and check permissions etc
mkdir -p $bdii_var_dir
mkdir -p $bdii_run_dir
mkdir -p $bdii_tmp_dir
mkdir -p $bdii_tmp_dir/ldif
mkdir -p $bdii_tmp_dir/provider
mkdir -p $bdii_tmp_dir/plugin

# change permissions if user is not root
chown -R ${bdii_user}: ${bdii_var_dir}
chown -R ${bdii_user}: ${bdii_run_dir}
chown -R ${bdii_user}: ${bdii_tmp_dir}


# Generate bdii configuration
rm -f ${BDII_CONF}
cat <<-EOF >> ${BDII_CONF}
	# This file was automatically generated by $0
	# Do not modify

	BDII_LOG_FILE=$bdii_log_file
	BDII_PID_FILE=$update_pid_file
	BDII_LOG_LEVEL=$bdii_debug_level
	BDII_LDIF_DIR=$bdii_ldif_dir
	BDII_PROVIDER_DIR=$bdii_provider_dir
	BDII_PLUGIN_DIR=$bdii_plugin_dir
	BDII_PORT=$bdii_port
	BDII_BREATHE_TIME=$bdii_breathe_time
	BDII_READ_TIMEOUT=$bdii_read_timeout
	BDII_ARCHIVE_SIZE=$bdii_archive_size
	BDII_DELETE_DELAY=$bdii_delete_delay
	BDII_USER=$bdii_user
	BDII_VAR_DIR=$bdii_var_dir
	BDII_RUN_DIR=$bdii_run_dir
	BDII_BIND=$bdii_bind
	SLAPD_CONF=$bdii_slapd_conf
	EOF

# Generate default ldif

cat <<-EOF > $bdii_default_ldif
	#!/usr/bin/perl

	# This file was automatically generated by $0
	# Do not modify

	use POSIX;

	print "\n";
	print "dn: o=grid\n";
	print "objectClass: organization\n";
	print "o: grid\n";
	print "\n";

	print "dn: Mds-Vo-name=local,o=grid\n";
	print "objectClass: Mds\n";
	print "Mds-Vo-name: local\n";
	print "Mds-validfrom: " . strftime("%Y%m%d%H%M%SZ\n", gmtime());
	print "Mds-validto: " . strftime("%Y%m%d%H%M%SZ\n", gmtime(time() + 3600));
	print "\n";

	print "dn: Mds-Vo-name=resource,o=grid\n";
	print "objectClass: Mds\n";
	print "Mds-Vo-name: resource\n";
	print "Mds-validfrom: " . strftime("%Y%m%d%H%M%SZ\n", gmtime());
	print "Mds-validto: " . strftime("%Y%m%d%H%M%SZ\n", gmtime(time() + 3600));
	print "\n";

	print "dn: o=glue\n";
	print "objectClass: organization\n";
	print "o: glue\n";
	EOF

    chmod +x $bdii_default_ldif

# Create ARC ldif generator file

ldif_generator_file=${bdii_tmp_dir}/provider/arc-nordugrid-bdii-ldif
rm -f ${ldif_generator_file}
touch ${ldif_generator_file}

ldif_script=${infosys_ldap_run_dir}/ldif-provider.sh

cat <<-EOF > ${ldif_generator_file}
	#!/usr/bin/perl
	
	# This file was automatically generated by the $0
	# Do not modify
	EOF

# NG and GLUE2 come directly from a-rex infoprovider
cat <<-EOF >> ${ldif_generator_file}
	
	BEGIN { unshift @INC, '$ARC_LOCATION/share/arc'; }
	use InfosysHelper;
	exit 1 unless InfosysHelper::ldifIsReady('$infosys_ldap_run_dir', '$max_cycle');
	EOF

if ${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys/nordugrid || \
   ${arcconfig_parser} --load -r ${ARC_RUNCONFIG} -b infosys/glue2/ldap; then
   echo "system('$ldif_script');" >> ${ldif_generator_file}
fi

chmod +x ${ldif_generator_file}

# Helper script to start BDII Update switching to BDII user
if [ -x /sbin/runuser ]; then
    RUNUSER=runuser
else
    RUNUSER=su
fi
USERSHELL=${USERSHELL:-"/bin/sh"}
if [ ! -x ${USERSHELL} ]; then
    log_failure_msg "Could not find ${USERSHELL}"
    exit 1
fi

cat <<-EOF > ${bdii_update_exechelper_cmd}
if [ \$( id -u ) = 0 ]; then
    exec $RUNUSER -s "$USERSHELL" -c "${bdii_update_cmd} -c ${BDII_CONF} -d" ${bdii_user}
else
    exec ${bdii_update_cmd} -c ${BDII_CONF} -d
fi
EOF

cat <<-EOF > ${bdii_update_posthelper_cmd}
iterlimit=30
while [ \$iterlimit -ge 0 ] && ! [ -r "${update_pid_file}" ]; do
  sleep 1
  iterlimit=\$(expr \$iterlimit - 1)
done
EOF

# copy forced pidfile to custom arc.conf pidfile (if needed)
if [ -n "${custom_pid_file}" ]; then
    echo "mkdir -p \"${custom_pid_file%/*}\"" >> ${bdii_update_posthelper_cmd}
    echo "cp -a \"${update_pid_file}\" \"${custom_pid_file}\"" >> ${bdii_update_posthelper_cmd}
fi
