#!/bin/bash
# Copyright (c) 2012 Cloudera, Inc. All rights reserved.

# Time marker for both stderr and stdout
date; date 1>&2

cloudera_config=`dirname $0`
cloudera_config=`cd "$cloudera_config/../common"; pwd`
. ${cloudera_config}/cloudera-config.sh

# attempt to find java
# We do not verify because finding JAVA_HOME isn't critical for client configs
locate_java_home_no_verify

# Load the parcel environment
source_parcel_environment

# Different environment variables are expected depending on whether we're
# deploying cluster or service client configs.

echo "using $JAVA_HOME as JAVA_HOME"

# (Service) service's cluster's CDH version (major only). Used to
# differentiate between deployment scenarios (cluster vs. service).
echo "using $CDH_VERSION as CDH_VERSION"

# (Both) absolute pathname representing the source configuration data
# directory (e.g. /var/run/cloudera-scm-agent/process/10-deploy-client-config).
echo "using $CONF_DIR as CONF_DIR"

# (Both) relative pathname representing a specific client config
# subdirectory within CONF_DIR (e.g. hbase-conf).
echo "using $DIRECTORY_NAME as DIRECTORY_NAME"

# (Service) absolute pathname where the alternatives link would point
# (e.g. /etc/hadoop/conf.cloudera.yarn1).
#
# (Cluster) absolute pathname representing the destination configuration
# data directory (e.g. for krb5.conf this would be /etc).
echo "using $DEST_PATH as DEST_PATH"

# (Service) name of entry in the alternatives database (e.g. hbase-conf).
echo "using $ALT_NAME as ALT_NAME"

# (Service) alternatives link (e.g. /etc/hbase/conf).
echo "using $ALT_LINK as ALT_LINK"

# (Service) priority for this alternatives link (e.g. 50).
echo "using $PRIORITY as PRIORITY"

# (Service) relative pathname to optional pre-deploy script.
echo "using $RUNNER_PROGRAM as RUNNER_PROGRAM"

# (Service) arguments for optional script, joined by spaces.
echo "using $RUNNER_ARGS as RUNNER_ARGS"

# (Service) update-alternatives location to be used by this script.
echo "using $UPDATE_ALTERNATIVES as UPDATE_ALTERNATIVES"

# debug
set -x
set -e

# Are we deploying cluster client configs? That's a much simpler operation
# wherein we skip the majority of this script.
if [[ "$CDH_VERSION" == -1 ]]; then
  echo "Deploying cluster client configs to $DEST_PATH"

  if [[ -e "$DEST_PATH" ]]; then
    # make sure it's a dir
    if [[ ! -d "$DEST_PATH" ]]; then
      echo "Destination directory is not a directory: $DEST_PATH"
      exit 1
    fi
  else
    # create dir
    mkdir -p "$DEST_PATH"
    if [[ 0 != $? ]]; then
      echo "Failed to create directory $DEST_PATH"
      exit 1
    fi
  fi

  # We're deploying to a shared directory, so leave all existing files intact.
  #
  # The deployment of a given file should be atomic to prevent racing with
  # existing readers. To guarantee that, we first copy the file to DEST_PATH's
  # filesystem. Then we overwrite the destination with mv.
  for TOCOPY in "$CONF_DIR/$DIRECTORY_NAME/"*
  do
    DEST_FILE="$DEST_PATH/$(basename $TOCOPY)"
    $SUDO cp -a "$TOCOPY" "$DEST_FILE.cm_tmp"
    chmod -R ugo+r "$DEST_FILE.cm_tmp"
    $SUDO mv -Tf "$DEST_FILE.cm_tmp" "$DEST_FILE"
  done

  exit 0
fi

echo "Deploying service client configs to $DEST_PATH"

if [[ $PARCELS_ROOT && $CDH_MR1_HOME = $PARCELS_ROOT/* ]]; then
  # Prefer symlink to actual parcel directory when MAPRED_HOME
  # is inside PARCELS_ROOT.  This improves the likelihood
  # that clients can survive an activation of a new parcel.
  CDH_MR1_HOME=${PARCELS_ROOT}/CDH/lib/hadoop-0.20-mapreduce
fi
if [[ $PARCELS_ROOT && $CDH_MR2_HOME = $PARCELS_ROOT/* ]]; then
  # Prefer symlink to actual parcel directory when MR2_HOME
  # is inside PARCELS_ROOT.  This improves the likelihood
  # that clients can survive an activation of a new parcel.
  CDH_MR2_HOME=${PARCELS_ROOT}/CDH/lib/hadoop-mapreduce
fi
# local replacement of substitution variables.
perl -pi -e "s#{{CDH_MR1_HOME}}#$CDH_MR1_HOME#g" "$CONF_DIR/$DIRECTORY_NAME/"*
perl -pi -e "s#{{CDH_MR2_HOME}}#$CDH_MR2_HOME#g" "$CONF_DIR/$DIRECTORY_NAME/"*
perl -pi -e "s#{{CDH_HADOOP_HOME}}#$CDH_HADOOP_HOME#g" "$CONF_DIR/$DIRECTORY_NAME/"*

# These substitutions are comments because if the client config is downloaded
# and not deployed; we don't want garbage in the file.
if [[ -n "$HADOOP_CLASSPATH" ]]; then
  perl -pi -e "s%# HADOOP_CLASSPATH={{HADOOP_CLASSPATH}}%export HADOOP_CLASSPATH=$HADOOP_CLASSPATH:\\\$HADOOP_CLASSPATH:%g" \
    "$CONF_DIR/$DIRECTORY_NAME/"*
  perl -pi -e "s%# HADOOP_CLASSPATH={{HADOOP_CLASSPATH_APPEND}}%export HADOOP_CLASSPATH=\\\$HADOOP_CLASSPATH:$HADOOP_CLASSPATH:%g" \
    "$CONF_DIR/$DIRECTORY_NAME/"*
fi
if [[ -n "$HBASE_CLASSPATH" ]]; then
  perl -pi -e "s%# HBASE_CLASSPATH={{HBASE_CLASSPATH}}%export HBASE_CLASSPATH=$HBASE_CLASSPATH:\\\$HBASE_CLASSPATH:%g" \
    "$CONF_DIR/$DIRECTORY_NAME/"*
fi
if [[ -n "$JAVA_LIBRARY_PATH" ]]; then
  perl -pi -e "s%# JAVA_LIBRARY_PATH={{JAVA_LIBRARY_PATH}}%export JAVA_LIBRARY_PATH=$JAVA_LIBRARY_PATH:\\\$JAVA_LIBRARY_PATH:%g" \
    "$CONF_DIR/$DIRECTORY_NAME/"*
fi
if [[ -n "$HIVE_AUX_JARS_PATH" ]]; then
  perl -pi -e "s%# HIVE_AUX_JARS_PATH={{HIVE_AUX_JARS_PATH}}%export HIVE_AUX_JARS_PATH=$HIVE_AUX_JARS_PATH,\\\$HIVE_AUX_JARS_PATH,%g" \
    "$CONF_DIR/$DIRECTORY_NAME/"*
fi

# replacement for HBASE_CONF_DIR
perl -pi -e "s#{{HBASE_CONF_DIR}}#$ALT_LINK#g" "$CONF_DIR/$DIRECTORY_NAME/"*

# replace SOLR_GATEWAY_CONF_DIR
perl -pi -e "s#{{SOLR_GATEWAY_CONF_DIR}}#$DEST_PATH#g" "$CONF_DIR/$DIRECTORY_NAME/"*

replace_hive_hbase_jars_template "$DIRECTORY_NAME/hive-env.sh"

# If the conf dir's parent doesn't exist, we have to create it
# as alternatives won't do it for us.
ROOT_DIR_NAME=`dirname $DEST_PATH`
if [ ! -e "$ROOT_DIR_NAME" ]; then
  $SUDO mkdir -p "$ROOT_DIR_NAME"
fi

# Special case handling for taskcontroller.cfg, container-executor.cfg
# These special files *must* exist in a specific location that typically
# collides with the expected client config location. As it is a file generated
# during role startup, we can't generate it as part of the client config, so
# we need to preserve it if it currently exists.
for SPECIAL_FILE in $DEST_PATH/{taskcontroller.cfg,container-executor.cfg}
do
  if [ -e $SPECIAL_FILE ]; then
    $SUDO cp -a $SPECIAL_FILE "$CONF_DIR/$DIRECTORY_NAME"
  fi
done

# If the conf dir isn't a symlink, then move it out of the way
# so alternatives can work. Specifically for hbase...
# See CDH-2980
LINK_BASENAME=`basename $ALT_LINK`
if [[ -d "$LINK_BASENAME" && ! -L "$LINK_BASENAME" ]]; then
  # This should be trivial with mv but Redhat didn't fix
  # it to work until 2011 in RHEL5.7 (original patch from 2006)
  # mv --backup=numbered $LINK_BASENAME $LINK_BASENAME.beforeClouderaManager
  TMP_NAME=`mktemp -d $LINK_BASENAME.beforeClouderaManager.XXXXXX`
  for file in `find $LINK_BASENAME -mindepth 1`; do
    mv "$file" $TMP_NAME/
  done
  rmdir $LINK_BASENAME
fi

# Run optional script if defined
if [ -n "$RUNNER_PROGRAM" ]; then
  # Make sure that the script is executable
  chmod u+x $CONF_DIR/$RUNNER_PROGRAM
  echo "invoking optional deploy script $RUNNER_PROGRAM"
  SRC_PATH="$CONF_DIR/$DIRECTORY_NAME"
  if [ ! -d $SRC_PATH ]; then
    echo "creating $SRC_PATH since it does not exist"
    mkdir $SRC_PATH
  fi
  pushd $SRC_PATH
  $CONF_DIR/$RUNNER_PROGRAM $RUNNER_ARGS
  echo "deploy script exited with $?"
  popd
fi

# Remove the old dir and replace with new dir.
#
# TEST_USER is only set in testing, never in production.
DEPLOYED_FILE_USER=${TEST_USER:-root}
$SUDO rm -rf "$DEST_PATH"
$SUDO cp -a "$CONF_DIR/$DIRECTORY_NAME" "$DEST_PATH"
$SUDO chown $DEPLOYED_FILE_USER "$DEST_PATH"
$SUDO chmod -R ugo+r "$DEST_PATH"

# topology.py needs to be marked as executable.
if [ -e $DEST_PATH/topology.py ]; then
  chmod +x $DEST_PATH/topology.py
fi

# TEST_UA_FLAGS is only set in testing, never in production.
$SUDO $UPDATE_ALTERNATIVES $TEST_UA_FLAGS --install "$ALT_LINK" "$ALT_NAME" "$DEST_PATH" $PRIORITY
$SUDO $UPDATE_ALTERNATIVES $TEST_UA_FLAGS --auto "$ALT_NAME"
