#!/bin/bash

#mode=EXACT/ANY/ALL
#LIST=pod~pod2~pod3
#NUM_NAME_CONT=3/alpine
#CLUSTER=cluter_name

#taking mode as 

#EXACT 0
#ANY 1
#ALL 2


MY_SCRIPT_NAME="$0"
UNIQUE_ID=`echo "$MY_SCRIPT_NAME" | cut -d '/' -f 3 | cut -d '_' -f 1`

DEBUG_LOG=/tmp/.nh_kube_util_${UNIQUE_ID}_$$.log
DEBUG_LEVEL=1
>${DEBUG_LOG}

WDIR=$1
POD_LIST=`echo $2 | tr '~' ' '`
MODE=$3
NUM_NAME_CONT=$4
FAULT=$5
CMD_ARGS=$6
ENABLE_COPY_HAVOC_SCRIPT=$7
CLUSTER=$8
Topology=$9
Namespace=${10}

#CONFIG_FILE="${WDIR}/netHavoc/kubernetes/conf/${CLUSTER}_config"
CONFIG_FILE="${WDIR}/mprof/${Topology}/cloud/kube/${CLUSTER}_config"

#kubectl argument to use specific file.
KUBE_CONF_FILE="--kubeconfig=${CONFIG_FILE}"

IS_MEM_FAULT=`echo ${FAULT} | grep -E "linux_fill_memory" >/dev/null 2>&1;echo $?`

RECIVED_ARG=$#
EXPECTED_ARG=10

ERROR="Error:"
STATUS=0

msgout ()
{
  echo "$*" >> ${DEBUG_LOG}
  echo "$*"
}

debug_log()
{
  if [ $DEBUG_LEVEL -eq 0 ]; then
    return
  else
    echo "[`date +"%D %T.%3N"`] [ $* ]" >> $DEBUG_LOG
  fi
}

write_status_and_exit()
{
  debug_log "write_status_and_exit: [Exit Output = $1, Exit Status =$2]"
  echo -n "$1"
  files_cleanup
  exit $2
}

files_cleanup()
{
  rm -f /tmp/${UNIQUE_ID}_netHavoc_kubernetes_utility.sh >> ${DEBUG_LOG} 2>&1
  rm -f /tmp/${UNIQUE_ID}_${FAULT} >> ${DEBUG_LOG} 2>&1
#  rm -f ${TEMP_OUTPUT_FILE} >> ${DEBUG_LOG} 2>&1
  rm -f /tmp/${UNIQUE_ID}_nh_fill_memory_utility >> ${DEBUG_LOG} 2>&1
  rm -f ${DEBUG_LOG}
}

Usage()
{
  msgout "Error :$1"
  msgout "Usage: netHavoc_kubernetes_utility.sh <POD_LIST> <MODE> <NUM_NAME_CONT> <FAULT> <CMD_ARGS> <ENABLE_COPY_HAVOC_SCRIPT> <CLUSTER><TOPOLOGY>"
  msgout "where:"
  msgout "  POD_LIST is for list of comma seperated multiple pods."
  msgout "	Ex- POD1,POD2,POD3"
  msgout "  MODE is for specify for how many contaires you want to apply havoc in one POD"
  msgout "	0- EXACT (to specify container name in pod)"
  msgout "	1- ANY (to use number of containers in pod)"
  msgout "	2- ALL (to use all containe exist in one pod)"
  msgout "  NUM_NAME_CONT is to sepecify name of container in case of MODE type EXACT also for number of container in case of MODE type ANY."
  msgout "  FAULT is to specify script name of fault"
  msgout "  CMD_ARGS is to pass arguments to fault script"
  msgout "  ENABLE_COPY_HAVOC_SCRIPT is to specify if you want to copy script from CMON"
  msgout "  CLUSTER is to specify cluster name you want to use"
  msgout "  TOPOLOGY is to specify topology you want to use"
  files_cleanup
  exit 1
}
check_agruments()
{
  if [ ${EXPECTED_ARG} -ne ${RECIVED_ARG} ];then
    Usage "argument count mismatch" 1
  fi

#<<comment   
#  if [ "XX${POD_LIST}" = "XX" ];then
#    Usage "Error: Pod list is blank" 1
#  elif [[ "${POD_LIST}" =~ ^[0-9a-z][0-9a-z]+$ ]]; then
#    Usage "Error: Pod list '${POD_LIST}' is having special character, only '-' is allowed." 1
#  fi
#comment 

  if [ ${MODE} -lt 0 -o ${MODE} -gt 2 ];then
    Usage "Error: Mode '${MODE}' is not valid." 1
  fi

  if [ "XX${CLUSTER}" = "XX" ];then
    Usage "Error: Cluster Name is blank" 1
  elif [[ "${CLUSTER}" =~ [^0-9a-zA-Z]+$ ]]; then
    Usage "Error: Cluster Name '${CLUSTER}' is having special character or space in it" 1
  fi
}


copy_havoc_script()
{
  #returning if copying of script is enabled through keyword ENABLE_COPY_SCRIPT in netHavoc.conf
  if [ ${ENABLE_COPY_HAVOC_SCRIPT} -eq 1 ];then
    return
  fi

  #If CAV_MON_HOME is not set then setting the CAV_MON_HOME to default path
  if [ "XX$CAV_MON_HOME" = "XX" ];then
    CAV_MON_HOME="/home/cavisson/monitors"
  fi

  #Checking if Havoc Script is present on Cmon or not.
  if [ ! -f $CAV_MON_HOME/netHavoc/${FAULT} ];then
    write_status_and_exit "Error: Unable to locate Havoc Script on cmon" 1
  fi

  #Checking If Fill Memory, If yes then also copy the fill memory utility
  #IS_MEM_FAULT=`echo ${FAULT} | grep -E "linux_fill_memory" >/dev/null 2>&1;echo $?`
  if [ $IS_MEM_FAULT -eq 0 ];then
    if [ ! -f $CAV_MON_HOME/netHavoc/nh_fill_memory_utility ];then
      write_status_and_exit "Error: Unable to locate Fill Memory Utility on cmon" 1
    fi
    cp $CAV_MON_HOME/netHavoc/nh_fill_memory_utility /tmp/${UNIQUE_ID}_nh_fill_memory_utility >> ${DEBUG_LOG} 2>&1
  fi

  #copying the havoc script
  cp ${CAV_MON_HOME}/netHavoc/${FAULT} /tmp/${UNIQUE_ID}_${FAULT} >> ${DEBUG_LOG} 2>&1

}

create_error_msg_on_failure()
{
  debug_log "Error: ${3}"
  ERROR="${ERROR} ${1}:${2} Failed. Reason:${3}"
  STATUS=1
}

check_os_and_copy_req_binaries()
{
  POD=${1}
  CONTAINER=${2}

  #check OS type of container
  OUTPUT=$(kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} --container ${CONTAINER} -- /bin/sh -c "cat /etc/os-release | grep -w NAME | cut -d '=' -f 2 | sed 's/\"//g'|sed -e 's/^M//g' | sed -e 's/\\r//g'" 2>&1)

  OS_RELEASE=`echo "${OUTPUT}"`
  if [ "XX${OS_RELEASE}" = "XX" ];then
    write_status_and_exit "Error: Unable to Check OS Release" "1"
  fi
  debug_log "container_os_release: [OS_RELEASE = ${OS_RELEASE}]"

  #check if network fault
  IS_NW_FAULT=`echo ${FAULT} | grep "_nw_" >/dev/null 2>&1;echo $?`
  if [ ${IS_NW_FAULT} -eq 0 ];then
    if [ "${OS_RELEASE}" = "Alpine Linux" ];then
      TAR_FILE="tc_alpine_linux.tar.gz"
    else
      TAR_FILE="tc_ubuntu.tar.gz"
    fi
    debug_log "IS_NW_FAULT=${IS_NW_FAULT} | TC_TAR_FILE = ${TAR_FILE}"
  fi

  #check if blackhole or dns fault
  IS_DNS_FAULT=`echo ${FAULT} | grep -E "_blackhole|_dns" >/dev/null 2>&1;echo $?`
  if [ ${IS_DNS_FAULT} -eq 0 ];then
    if [ "${OS_RELEASE}" = "Alpine Linux" ];then
      TAR_FILE="iptable_alpine_linux.tar.gz"
    else
      TAR_FILE="iptable_ubuntu.tar.gz"
    fi
    debug_log "IS_DNS_FAULT=${IS_DNS_FAULT}| IPTABLE_TAR_FILE = ${TAR_FILE}"
  fi

  #check if IO fault
  IS_IO_FAULT=`echo ${FAULT} | grep -E "_io_" >/dev/null 2>&1;echo $?`
  if [ ${IS_IO_FAULT} -eq 0 ];then
    TAR_FILE="dd_tool.tar.gz"
    debug_log "IS_IO_FAULT=${IS_IO_FAULT} | DD_TOOL_TAR_FILE = {$TAR_FILE}"
  fi

  #copy tar file to {POD}:{CONTAINER} if any of type fault match
  if [ ${IS_IO_FAULT} -eq 0 ] || [ ${IS_DNS_FAULT} -eq 0 ] || [ ${IS_NW_FAULT} -eq 0 ];then
    if [ ! -f ${CAV_MON_HOME}/netHavoc/${TAR_FILE} ];then
      create_error_msg_on_failure "${POD}" "${CONTAINER}" "Error: Unable to locate required binary on cmon" 1
      return 1
    fi

    debug_log "kubectl ${KUBE_CONF_FILE} cp ${CAV_MON_HOME}/netHavoc/${TAR_FILE} -n ${Namespace} ${POD}:/tmp  -c ${CONTAINER}"
    OUTPUT=$(kubectl ${KUBE_CONF_FILE} cp ${CAV_MON_HOME}/netHavoc/${TAR_FILE} -n ${Namespace} ${POD}:/tmp  -c ${CONTAINER} 2>&1)
    if [ "$?" != "0" ];then
      create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
      return 1
    fi

    #creating havoc id directory
    debug_log "kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} --container ${CONTAINER} -- mkdir -p /tmp/$UNIQUE_ID"
    OUTPUT=$(kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} --container ${CONTAINER} -- mkdir -p /tmp/$UNIQUE_ID 2>&1)
    if [ "$?" != "0" ];then
      create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
      return 1
    fi

    #untar on container
    debug_log "kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} --container ${CONTAINER} -- tar -xzf /tmp/${TAR_FILE} -C /tmp/$UNIQUE_ID"
    OUTPUT=$(kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} --container ${CONTAINER} -- tar -xzf /tmp/${TAR_FILE} -C /tmp/$UNIQUE_ID 2>&1)
    if [ "$?" != "0" ];then
      create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
      return 1
    fi
  fi

  return 0
}



copy_and_run_fault()
{
  POD=${1}
  CONTAINER=${2}
  
  IS_KILL_SERVER_FAULT=`echo ${FAULT} | grep -E "server_termination" >/dev/null 2>&1;echo $?`
  if [ ${IS_KILL_SERVER_FAULT} -eq 0 ];then
    #Shutdown-0 Reboot-1
    OPERATION=`echo $CMD_ARGS | cut -d ' ' -f2`
    debug_log "OPERATION=${OPERATION}"
    DELAY=`echo $CMD_ARGS | cut -d ' ' -f1`
    DELAY_TIME=`expr ${DELAY} \* 60`
    debug_log "DELAY_TIME=${DELAY_TIME}"
    if [ $DELAY -ne 0 ];then
      sleep $DELAY_TIME
    fi

    if [ $OPERATION -eq 0 ];then
      debug_log "kubectl ${KUBE_CONF_FILE} delete pod ${POD} -n ${Namespace}"
      OUTPUT=$(kubectl ${KUBE_CONF_FILE} delete pod ${POD} -n ${Namespace} 2>&1)
      if [ "$?" != "0" ];then
        create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
        return
      fi
    elif [ $OPERATION -eq 1 ];then
      debug_log "kubectl ${KUBE_CONF_FILE} get pod ${POD} -n ${Namespace} -o yaml | kubectl ${KUBE_CONF_FILE} replace --force -f -"
      OUTPUT=$(kubectl ${KUBE_CONF_FILE} get pod ${POD} -n ${Namespace} -o yaml | kubectl ${KUBE_CONF_FILE} replace --force -f - 2>&1)
      if [ "$?" != "0" ];then
        create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
        return
      fi
    fi
    return
  fi

    #hovoc files copy 
  if [ $IS_MEM_FAULT -eq 0 ];then
    debug_log "kubectl ${KUBE_CONF_FILE} cp /tmp/${UNIQUE_ID}_nh_fill_memory_utility ${POD}:/tmp  -n ${Namespace} -c ${CONTAINER}"
    OUTPUT=$(kubectl ${KUBE_CONF_FILE} cp /tmp/${UNIQUE_ID}_nh_fill_memory_utility ${POD}:/tmp  -n ${Namespace} -c ${CONTAINER} 2>&1)
    if [ "$?" != "0" ];then
      create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
      return
    fi
  fi
  debug_log "kubectl ${KUBE_CONF_FILE} cp /tmp/${UNIQUE_ID}_${FAULT} ${POD}:/tmp  -n ${Namespace} -c ${CONTAINER}"
  OUTPUT=$(kubectl ${KUBE_CONF_FILE} cp /tmp/${UNIQUE_ID}_${FAULT} ${POD}:/tmp  -n ${Namespace} -c ${CONTAINER} 2>&1)
  if [ "$?" != "0" ];then
    create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
    return
  fi

  #check container os type and copy
  check_os_and_copy_req_binaries "${POD}" "${CONTAINER}"
  if [ "$?" != "0" ];then
    return
  fi
 
  #change all file to root
  OUTPUT=$(kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} --container ${CONTAINER} -- /bin/sh -c "chown root:root /tmp/*" 2>&1)
  if [ "$?" != "0" ];then
    create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
    return
  fi



  #start havoc execution.
  debug_log "kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} -i --container ${CONTAINER} -- /bin/sh \'/tmp/${UNIQUE_ID}_${FAULT} ${CMD_ARGS}\'"
  OUTPUT=$(kubectl ${KUBE_CONF_FILE} exec ${POD} -n ${Namespace} -i --container ${CONTAINER} -- /bin/sh -c "/tmp/${UNIQUE_ID}_${FAULT} ${CMD_ARGS}" 2>&1)
  echo $OUTPUT|grep -E 'Success' >> ${DEBUG_LOG} 2>&1
  if [ "$?" != "0" ];then
    create_error_msg_on_failure "${POD}" "${CONTAINER}" "${OUTPUT}"
    return
  fi
}

copy_and_run_fault_on_containers()
{
  for POD in ${POD_LIST}
  do 
    if [ ${MODE} -eq 0 ];then    #EXACT 
      copy_and_run_fault "${POD}" "${NUM_NAME_CONT}"   
    else  #case of any and all

      #fetch container list on pod
      debug_log "kubectl ${KUBE_CONF_FILE} get pods ${POD} -n ${Namespace} -o jsonpath='{.spec.containers[*].name}'"
      CONTAINERS=$(kubectl ${KUBE_CONF_FILE} get pods ${POD} -n ${Namespace} -o jsonpath='{.spec.containers[*].name}' 2>&1) 
      if [ "$?" != "0" ];then
        create_error_msg_on_failure "${POD}" "CONTAINER LIST" "${CONTAINERS}"
        continue
      fi
      
      if [ ${MODE} -eq 1 ];then  #ANY
        ITERATION=0
        for CONTAINER in ${CONTAINERS}
        do
          if [ ${ITERATION} -eq ${NUM_NAME_CONT} ];then
            break
          fi
          ITERATION=`expr ${ITERATION} + 1`
          copy_and_run_fault "${POD}" "${CONTAINER}"   
        done
      elif [ ${MODE} -eq 2 ];then  #ALL
        for CONTAINER in ${CONTAINERS}
        do
          copy_and_run_fault "${POD}" "${CONTAINER}"   
        done
      fi
    fi
  done 

  if [ ${STATUS} -ne 0 ];then
    write_status_and_exit "${ERROR}" ${STATUS}
  fi
}

#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++EXECUTION START FROM HERE+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

check_agruments
copy_havoc_script
copy_and_run_fault_on_containers

write_status_and_exit "Success" 0
