#!/bin/bash

# CONTROLLING STARTUP:
#
# This script relies on a few environment variables to determine startup
# behavior, those variables are:
#
#   ES_PATH_CONF -- Path to config directory
#   ES_JAVA_OPTS -- External Java Opts on top of the defaults set
#
# Optionally, exact memory values can be set using the `ES_JAVA_OPTS`. Example
# values are "512m", and "10g".
#
#   ES_JAVA_OPTS="-Xms8g -Xmx8g" ./bin/elasticsearch

source "`dirname "$0"`"/elasticsearch-env

CHECK_KEYSTORE=true
ATTEMPT_SECURITY_AUTO_CONFIG=true
DAEMONIZE=false
ENROLL_TO_CLUSTER=false
# Store original arg array as we will be shifting through it below
ARG_LIST=("$@")

while [ $# -gt 0 ]; do
   if [[ $1 == "--enrollment-token" ]]; then
     if [ $ENROLL_TO_CLUSTER = true ]; then
       echo "Multiple --enrollment-token parameters are not allowed" 1>&2
       exit 1
     fi
     ENROLL_TO_CLUSTER=true
     ATTEMPT_SECURITY_AUTO_CONFIG=false
     ENROLLMENT_TOKEN="$2"
     shift
   elif [[ $1 == "-h" || $1 == "--help" || $1 == "-V" || $1 == "--version" ]]; then
     CHECK_KEYSTORE=false
     ATTEMPT_SECURITY_AUTO_CONFIG=false
   elif [[ $1 == "-d" || $1 == "--daemonize" ]]; then
     DAEMONIZE=true
   fi
   if [[ $# -gt 0 ]]; then
     shift
   fi
done

if [ -z "$ES_TMPDIR" ]; then
  ES_TMPDIR=`"$JAVA" "$XSHARE" -cp "$ES_CLASSPATH" org.elasticsearch.tools.launchers.TempDirectory`
fi

# get keystore password before setting java options to avoid
# conflicting GC configurations for the keystore tools
unset KEYSTORE_PASSWORD
KEYSTORE_PASSWORD=
if [[ $CHECK_KEYSTORE = true ]] \
    && bin/elasticsearch-keystore has-passwd --silent
then
  if ! read -s -r -p "Elasticsearch keystore password: " KEYSTORE_PASSWORD ; then
    echo "Failed to read keystore password on console" 1>&2
    exit 1
  fi
fi

if [[ $ENROLL_TO_CLUSTER = true ]]; then
  ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.AutoConfigureNode \
  ES_ADDITIONAL_SOURCES="x-pack-env;x-pack-security-env" \
  ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli \
  bin/elasticsearch-cli "${ARG_LIST[@]}" <<<"$KEYSTORE_PASSWORD"
elif [[ $ATTEMPT_SECURITY_AUTO_CONFIG = true ]]; then
  # It is possible that an auto-conf failure prevents the node from starting, but this is only the exceptional case (exit code 1).
  # Most likely an auto-conf failure will leave the configuration untouched (exit codes 73, 78 and 80), optionally printing a message
  # if the error is uncommon or unexpected, but it should otherwise let the node to start as usual.
  # It is passed in all the command line options in order to read the node settings ones (-E), while the other parameters are ignored
  # (a small caveat is that it also inspects the -v option in order to provide more information on how auto config went)
  if ES_MAIN_CLASS=org.elasticsearch.xpack.security.cli.AutoConfigureNode \
    ES_ADDITIONAL_SOURCES="x-pack-env;x-pack-security-env" \
    ES_ADDITIONAL_CLASSPATH_DIRECTORIES=lib/tools/security-cli \
    bin/elasticsearch-cli "${ARG_LIST[@]}" <<<"$KEYSTORE_PASSWORD"; then
      :
  else
    retval=$?
    # these exit codes cover the cases where auto-conf cannot run but the node should NOT be prevented from starting as usual
    # eg the node is restarted, is already configured in an incompatible way, or the file system permissions do not allow it
    if [[ $retval -ne 80 ]] && [[ $retval -ne 73 ]] && [[ $retval -ne 78 ]]; then
      exit $retval
    fi
  fi
fi

# The JVM options parser produces the final JVM options to start Elasticsearch.
# It does this by incorporating JVM options in the following way:
#   - first, system JVM options are applied (these are hardcoded options in the
#     parser)
#   - second, JVM options are read from jvm.options and jvm.options.d/*.options
#   - third, JVM options from ES_JAVA_OPTS are applied
#   - fourth, ergonomic JVM options are applied
ES_JAVA_OPTS=`export ES_TMPDIR; "$JAVA" "$XSHARE" -cp "$ES_CLASSPATH" org.elasticsearch.tools.launchers.JvmOptionsParser "$ES_PATH_CONF" "$ES_HOME/plugins"`

# Remove enrollment related parameters before passing the arg list to Elasticsearch
for i in "${!ARG_LIST[@]}"; do
  if [[ ${ARG_LIST[i]} = "--enrollment-token" || ${ARG_LIST[i]} = "$ENROLLMENT_TOKEN" ]]; then
    unset 'ARG_LIST[i]'
  fi
done

# manual parsing to find out, if process should be detached
if [[ $DAEMONIZE = false ]]; then
  exec \
    "$JAVA" \
    "$XSHARE" \
    $ES_JAVA_OPTS \
    -Des.path.home="$ES_HOME" \
    -Des.path.conf="$ES_PATH_CONF" \
    -Des.distribution.flavor="$ES_DISTRIBUTION_FLAVOR" \
    -Des.distribution.type="$ES_DISTRIBUTION_TYPE" \
    -Des.bundled_jdk="$ES_BUNDLED_JDK" \
    -cp "$ES_CLASSPATH" \
    org.elasticsearch.bootstrap.Elasticsearch \
    "${ARG_LIST[@]}" <<<"$KEYSTORE_PASSWORD"
else
  exec \
    "$JAVA" \
    "$XSHARE" \
    $ES_JAVA_OPTS \
    -Des.path.home="$ES_HOME" \
    -Des.path.conf="$ES_PATH_CONF" \
    -Des.distribution.flavor="$ES_DISTRIBUTION_FLAVOR" \
    -Des.distribution.type="$ES_DISTRIBUTION_TYPE" \
    -Des.bundled_jdk="$ES_BUNDLED_JDK" \
    -cp "$ES_CLASSPATH" \
    org.elasticsearch.bootstrap.Elasticsearch \
    "${ARG_LIST[@]}" \
    <<<"$KEYSTORE_PASSWORD" &
  retval=$?
  pid=$!
  [ $retval -eq 0 ] || exit $retval
  if ! ps -p $pid > /dev/null ; then
    exit 1
  fi
  exit 0
fi

exit $?
