#!/bin/bash

set -e

function usage
{
  echo
  if [ "$*" != "" ]
  then
    echo "===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!"
    echo
    echo "$*"
    echo
    echo "===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!===!!!"
    
  else
    echo "Cleanup SLA in MongoDb by removing elements which are no more"
    echo "* in production configuration"
    echo "* in stagging configuration"
  fi
  echo
  echo "USAGE: ${0##*/}"
  echo 
  echo "--help                          this help screen"
  echo "-H HOSTNAME, --host HOSTNAME    mongo server name (default: localhost)"
  echo "-p PORT, --port PORT            mongo server port (default: 27017)"
  echo "-w WORK_DIR, --workdir WORK_DIR directory used to store temporary files (best "
  echo "                                suited in memory filesystem) "
  echo "                                (default:/dev/shm/shinken-clean-sla)"
  echo "-d delay, --pause-delay delay   after batch-size elements have been removed "
  echo "                                make a pause of delay milliseconds"
  echo "                                (default: 200)"
  echo "-s size, --batch-size size      number of elements to delete in Mongodb before"
  echo "                                making a pause "
  echo "                                (default:no limit) "
  echo "-c, --clean                     remove temporary files from previous run and "
  echo "                                exit"
  exit 2
}

### Parameters parsing ###

MONGO_HOST="localhost"
MONGO_PORT="27017"
DAYS_RANGE="90"
WORKDIR="/dev/shm/shinken-clean-sla"

while [ $# -gt 0 ]
do
  case $1 in
    -H|--host)
      [ $# -lt 2 ] && usage "missing host name value"
      MONGO_HOST="$2"
      shift 2
      ;;
    -p|--port)
      [ $# -lt 2 ] && usage "missing port number value"
      [ "$2" -gt 0 ] || usage "incorrect port number [$2]"
      MONGO_PORT="$2"
      shift 2
      ;;
    -w|--workdir)
      [ $# -lt 2 ] && usage "missing workdir value"
      WORKDIR="$2"
      shift 2
      ;;
    -s|--batch-size)
      [ $# -lt 2 ] && usage "missing batch size value"
      BATCH="$2"
      shift 2
      ;;
    -d|--pause-delay)
      [ $# -lt 2 ] && usage "missing pause delay value"
      PAUSE="$2"
      shift 2
      ;;
    -c|--clean)
      CLEANUP_MODE="yes"
      shift
      ;;
    -h|--help|*)
      usage
      ;;
  esac     
done


### Permission check in working dir ###

[ -d "${WORKDIR}" ] || mkdir -vp "${WORKDIR}"

cd "${WORKDIR}" || usage "[ ${WORKDIR} ]: Can not change current directory, please check permissions"

echo test > "./${$}.txt" || usage "[ ${WORKDIR} ]: Can not write into directory, please check permissions"

\rm -f "./${$}.txt"


SLA_UUID=./all.uuid
CONF_ACTIVE_HOSTS_FILE=./conf_active.uuid
DELETED_HOSTS_FILE=./deleted_hosts.uuid
CLEANED_ELEMENTS_FILE=./cleaned.uuid
TODO_FILE=./todo.uuid

if [ -n "${CLEANUP_MODE}" ]
then
  echo -n "Cleaning up ... "
  \rm -f ${SLA_UUID} ${CONF_ACTIVE_HOSTS_FILE} ${DELETED_HOSTS_FILE} ${CLEANED_ELEMENTS_FILE} ${TODO_FILE}
  echo "done"
  exit 0
fi

renice 5 $$ &>/dev/null

### Parameter setting ###

MONGO_TARGET="${MONGO_HOST}:${MONGO_PORT}"

echo "Will connect to mongo at ${MONGO_TARGET}"

if [ -n "${BATCH}" ]
then
  if [ "${BATCH}" -gt 0 ] &>/dev/null
  then
    BATCH_SIZE=$(( ${BATCH} + 0 ))
    if [ -z "${PAUSE}" ]
    then
      PAUSE=200
    fi
  else
    usage "Incorrect value [ ${BATCH} ] for batch size, must be an integer"
  fi
fi

if [ -n "${PAUSE}" ]
then
  if [ "${PAUSE}" -gt 0 ] &>/dev/null
  then
    PAUSE_DELAY=$(printf "%d.%0.3d" $((${PAUSE}/1000)) $((${PAUSE}%1000)) )
    if [ -z "${BATCH_SIZE}" ]
    then
      usage "Pause delay has been changed to ${PAUSE_DELAY} seconds, but no batch size has been set"
    fi
    echo "Will make pause of ${PAUSE_DELAY} seconds after ${BATCH_SIZE} deletions"
  else
    usage "Incorrect value [ ${PAUSE} ] for pause value, must be an integer"
  fi
fi

# Get all UUID from sla_info
[ -s "${SLA_UUID}" ] || {
  echo -n 'Collecting data from database ... ';
  
  # Prevent Control-C interruption only for this read operation
  trap '' SIGINT
  mongo --quiet ${MONGO_TARGET}/shinken --eval "db.getCollection('sla_info').find({_id: {\$ne: 'SLA_INFO'}}).forEach(function (data) {print(data._id)})" > "${SLA_UUID}.tmp";
  \mv "${SLA_UUID}.tmp" "${SLA_UUID}";
  
  # Restore ability to interrupt by Control-C 
  trap -- SIGINT
  echo 'done';
}

if [ ! -e "${TODO_FILE}" ]
then
  # Compute remaining job (if restarted and no todo file)
  sort "${SLA_UUID}" > "${SLA_UUID}.tmp"
  \mv "${SLA_UUID}.tmp" "${TODO_FILE}"
  for F in "${CLEANED_ELEMENTS_FILE}" "${CONF_ACTIVE_HOSTS_FILE}" "${DELETED_HOSTS_FILE}"
  do
    if [ -s "${F}" ]
    then
      sort "${F}" > "${F}.tmp"
      \mv "${F}.tmp" "${F}"
      comm -2 -3 "${TODO_FILE}" "${F}" > "${TODO_FILE}.tmp"
      \mv "${TODO_FILE}.tmp" "${TODO_FILE}"
    fi
  done
fi

function remove_from_search () {
    grep -v "^${1}" "${TODO_FILE}" > "${TODO_FILE}.tmp"
    \mv "${TODO_FILE}.tmp" "${TODO_FILE}"
}

function clean_sla
{
  DELETED=$(mongo --quiet ${MONGO_TARGET}/shinken --eval "archive_del = db.runCommand({ delete:'sla_archive', deletes: [ {q: {'uuid': '${1}'} , limit: 0} ]}); info_del = db.runCommand({ delete: 'sla_info', deletes: [ {q: {'_id': '${1}'}, limit: 0} ] } ); print(archive_del.n + info_del.n)" )
  echo "$1" >> ${CLEANED_ELEMENTS_FILE}

  if [ -n "${BATCH_SIZE}" -a -n "${PAUSE_DELAY}" ]
  then
    BATCH_DELETED=$(( ${BATCH_DELETED} + ${DELETED} ))
    if [ ${BATCH_DELETED} -gt ${BATCH_SIZE} ]
    then
      BATCH_DELETED=0
      sleep ${PAUSE_DELAY} &>/dev/null || true
    fi
  fi
}

function log_debug {
  echo "$*" 1>&2
}


TOTAL=$(wc -l < ${SLA_UUID})
BATCH_DELETED=0
LAST_PROGRESSION=0
echo -n "Progression (%) : 0"
while [ -s ${TODO_FILE} ]
do
  read UUID < ${TODO_FILE}
  
  PROGRESSION=$((100 - ($(wc -l < ${TODO_FILE}) * 100 / ${TOTAL})))
  if [ ${LAST_PROGRESSION} -ne ${PROGRESSION} ]
  then
    echo -ne "${LAST_PROGRESSION//?/\b}${PROGRESSION}"
    LAST_PROGRESSION=${PROGRESSION}
  fi
  HOST_UUID=${UUID%%-*}

  if grep -qs "^${HOST_UUID}" ${CONF_ACTIVE_HOSTS_FILE}
  then
    remove_from_search ${HOST_UUID}
    continue
  fi
  if grep -qs "^${UUID}$" ${CLEANED_ELEMENTS_FILE}
  then
    remove_from_search ${UUID}
    continue
  fi

  if grep -qs "^${HOST_UUID}" ${DELETED_HOSTS_FILE}
  then
    clean_sla ${UUID}
    remove_from_search ${UUID}
    continue
  fi

  CONF=$(mongo --quiet ${MONGO_TARGET}/synchronizer --eval "db.getCollection('configuration-production-host').find({'_id': '${HOST_UUID}'}).limit(1).forEach(printjson); db.getCollection('configuration-stagging-host').find({'_id': '${HOST_UUID}'}).limit(1).forEach(printjson)")

  if [ -n "${CONF}" ]
  then
    echo ${HOST_UUID} >> ${CONF_ACTIVE_HOSTS_FILE}
    remove_from_search ${HOST_UUID}
    continue
  fi

  echo ${HOST_UUID} >> ${DELETED_HOSTS_FILE}

  for UUID in $(grep "^${HOST_UUID}" ${TODO_FILE} )
  do
    clean_sla ${UUID}
  done
  remove_from_search ${HOST_UUID}
done
