#!/bin/bash

HOSTNAME=$(ngcp-hostname)
NGCP_ROLES_FILE='/etc/default/ngcp-roles'
DB_CONF='/etc/default/ngcp-db'
SYNC_DBS=()

# helper function
usage () {
  echo -e "\n$0 - wrapper to simplify ngcp-sync-db usage"
  echo -e "   Run the script from the node where you have the replication issue."
  echo -e "   The node should be PASSIVE.\n"
  exit 0
}

case "${1}" in
  -h|--help) usage ;;
esac


# Reading information from ngcp-roles
if ! [ -r "${NGCP_ROLES_FILE}" ] ; then
  echo "Error: can't read file ${NGCP_ROLES_FILE} !" >&2
  exit 1
fi

# shellcheck disable=SC1090
. "${NGCP_ROLES_FILE}"

if [ -z "${NGCP_IS_GEO_CLUSTER}" ] || [ -z "${NGCP_TYPE}" ] || [ -z "${NGCP_HOSTNAME}" ] || [ -z "${NGCP_PEERNAME}" ] ; then
  echo "Error: missing information in ${NGCP_ROLES_FILE}, cannot continue!" >&2
  exit 1
fi

if [ "${NGCP_IS_GEO_CLUSTER}" == "yes" ] ; then
  echo "${0} does not support geo-cluster setup" >&2
  exit 1
fi

# Reading mediator and rate-o-mat configurations to check if they are running or not
#  - If the replication is on pair node should be on/off in both
#  - If the replication is on central node in any case I have to check the local one
if ! ngcp-service mediator is-managed >/dev/null 2>&1; then
  echo "Error: Mediator is not running" >&2
  RUN_MEDIATOR="no"
else
  RUN_MEDIATOR="yes"
fi

if ! ngcp-service rateomat is-managed >/dev/null 2>&1; then
  echo "Rate-o-mat it is not running" >&2
  RATEOMAT_RUN="no"
else
  RATEOMAT_RUN="yes"
fi


# Reading databases information (ip and port)
if ! [ -r "${DB_CONF}" ] ; then
  if ${OUTPUT} ; then
    echo "Error: can't read file ${DB_CONF} !" >&2
  fi
  exit 1
fi

# shellcheck disable=SC1090
. "${DB_CONF}"

#======================================================================
main() {
  # Check the platform type
  case "${NGCP_TYPE}" in
        spce) echo -e "\nSystem detected as CE. CE platform is not supported. Exiting." >&2
              exit 1
              ;;
       sppro) echo -e "\nSystem detected as PRO."
              pro_prepare
              ;;
     carrier) echo -e "\nSystem detected as CARRIER."
              carrier_prepare
              ;;
           *) echo -e "\nNo system detected. Exiting." >&2
              exit 1
  esac

  local_backup=false

  check_connectivity
  fix_replication

  if "${local_backup}" ; then
    echo -e "\nPlease find db backups in /ngcp-data/backup/ngcp-sync-db.\n"
  fi

  return 0
}


#----------------------------------------------------------------------
# Ask for confirmation to proceed
confirmation() {
  while true ; do
    echo "Do you want to continue (yes/no)? "
    read -r choice
    case "${choice,,}" in
      yes) break;;
      no) echo "Exiting" && exit 0;;
      *) echo "Invalid choice. Enter yes or no, please";;
    esac
  done

  return 0
}


#----------------------------------------------------------------------
# Check connectivity first between nodes
check_connectivity() {
  echo -e "\nCheck connectivity from ${SLAVENODE} to ${MASTERNODE} ..."
  if ping -q -c3 "${MASTERNODE}" > /dev/null 2>&1 ; then
    echo "${MASTERNODE} is reachable."
  else
    echo "${MASTERNODE} unreachable. Please fix it." >&2
    exit 1
  fi

  return 0
}


#----------------------------------------------------------------------
# PRO: prepare the fix of replica between sp1 and sp2
# The script should be executed from the PASSIVE node where the issue is present
pro_prepare() {
  # detect current node
  CURRENTNODE="${HOSTNAME}"
  SLAVENODE="${NGCP_HOSTNAME}"
  MASTERNODE="${NGCP_PEERNAME}"

  MASTERPORT="${PAIR_DBPORT}"
  SLAVEPORT="${PAIR_DBPORT}"

  # check active/passive node
  if ngcp-check-active ; then
    # current node is active
    echo -e "\nActive node MUST NOT be local host. Restoring the database on this node can lead to downtime."
    confirmation
    SERVICES_NODE="${SLAVENODE}"
  else
    SERVICES_NODE="${MASTERNODE}"
  fi

  SCRIPT_OPT=(-v --master-host="${MASTERNODE}" --master-port="${MASTERPORT}" --local-host="${CURRENTNODE}" --local-port="${SLAVEPORT}" --sync-mode=backup --local-backup --keep-backups --fix-db-schema)
  local_backup=true

  echo "Requested to fix replication between master node ${MASTERNODE} and slave node ${SLAVENODE}"

  return 0
}


#----------------------------------------------------------------------
# CARRIER: check which type of replica should be fixed
carrier_prepare() {
  while true ; do
    echo "Do you need to sync mysql from central node (yes/no) ? "
    read -r FROMCENTRAL
    FROMCENTRAL="${FROMCENTRAL,,}"
    case "${FROMCENTRAL}" in
      yes|no) break;;
      *) echo "Invalid choice. Enter yes or no, please";;
    esac
  done

  # Fix replication on carrier between proxy/icn and db node
  if [ "${FROMCENTRAL}" == "yes" ] ; then
    echo ""
    while true ; do
      echo "Do you need to sync a PROXY node or a ICN (proxy/icn) ? "
      read -r PROXYICN
      PROXYICN="${PROXYICN,,}"
      case "${PROXYICN}" in
        proxy|icn) break;;
        *) echo "Invalid choice. Enter proxy or icn, please";;
      esac
    done

    if [ "$PROXYICN" == "icn" ] ; then
      if [ "${NGCP_IS_LB}" == "no" ] ; then
        # current node is not an ICN
        echo "This is not an ICN node. Exiting" >&2
        exit 1
      fi
      SYNC_DBS=(mysql billing)
      carrier_central_prepare

    elif [ "$PROXYICN" == "proxy" ] ; then
      if [ "${NGCP_IS_PROXY}" == "no" ] ; then
        # current node is not a proxy
        echo "This is not a PROXY node. Exiting" >&2
        exit 1
      fi
      SYNC_DBS=(mysql billing carrier kamailio provisioning prosody)
      carrier_central_prepare

    else
      # It should never match
      echo "Invalid choice. Exiting." >&2
      exit 1
    fi

  # Fix replication on carrier between sp1 and sp2
  elif [ "${FROMCENTRAL}" = "no" ] ; then
    carrier_sp_prepare

  else
    # It should never match
    echo "Invalid choice. Exiting." >&2
    exit 1

  fi

  return 0
}


#----------------------------------------------------------------------
# CARRIER: prepare the fix of replica between sp1 and sp2
carrier_sp_prepare() {
  # detect current node
  CURRENTNODE="${HOSTNAME}"
  SLAVENODE="${NGCP_HOSTNAME}"
  MASTERNODE="${NGCP_PEERNAME}"

  MASTERPORT="${PAIR_DBPORT}"
  SLAVEPORT="${PAIR_DBPORT}"

  # check active/passive node
  if ngcp-check-active ; then
    # current node is active
    echo -e "\nActive node MUST NOT be local host. Restoring the database on this node can lead to downtime."
    confirmation
    SERVICES_NODE="${SLAVENODE}"
  else
    SERVICES_NODE="${MASTERNODE}"
  fi

  SCRIPT_OPT=(-v --master-host="${MASTERNODE}" --master-port="${MASTERPORT}" --local-host=localhost --local-port="${SLAVEPORT}" --sync-mode=backup --local-backup --keep-backups --fix-db-schema)
  local_backup=true

  echo "Requested to fix replication between master node ${MASTERNODE} and slave node ${SLAVENODE}"

  return 0
}


#----------------------------------------------------------------------
# CARRIER: prepare the fix of replica between db and proxy or icn nodes
carrier_central_prepare() {
  # check active/passive node
  if ngcp-check-active ; then
    # current node is active
    echo -e "\nActive node MUST NOT be local host. Restoring the database on this node can lead to downtime."
    confirmation
  fi

  # detect current node
  CURRENTNODE="${HOSTNAME}"
  SLAVENODE="${NGCP_HOSTNAME}"
  MASTERNODE="db01"
  MASTERPORT="${CENTRAL_DBPORT}"
  SLAVEPORT="${LOCAL_DBPORT}"

  SERVICES_NODE="${CURRENTNODE}"

  SCRIPT_OPT=(-v --local-host="${CURRENTNODE}" --use-central-db --repl-mode master-slave --databases "${SYNC_DBS[@]}")

  echo "Requested to fix replication between master db node ${MASTERNODE} and slave proxy node ${SLAVENODE}"

  return 0
}


#----------------------------------------------------------------------
# Stop mediator and rate-o-mat if the script is running on PRO or proxy node
stop_services() {
  if [ "${NGCP_IS_PROXY}" == "yes" ] ; then

    if [ "${SERVICES_NODE}" == "${CURRENTNODE}" ] ; then
      if ngcp-check-active ; then
        echo -e "\nTo proceed I need to stop mediator and rate-o-mat service on local node."
        confirmation

        echo "Stopping mediator and rate-o-mat on local (${SERVICES_NODE}) node:"
        if [ "${RUN_MEDIATOR}" == "yes" ] ; then
          echo "Stopping mediator..."
          ngcp-service mediator stop
          sleep 5
        else
          echo "Mediator not enabled."
        fi
        if [ "${RATEOMAT_RUN}" == "yes" ] ; then
          echo "Stopping rate-o-mat..."
          ngcp-service rateomat stop
          sleep 5
        else
          echo "Rate-o-mat not enabled."
        fi
      fi

    else
      echo -e "\nTo proceed I need to stop mediator and rate-o-mat service on the remote node."
      confirmation

      echo "Stopping mediator and rate-o-mat on remote (${SERVICES_NODE}) node:"
      if [ "${RUN_MEDIATOR}" == "yes" ] ; then
        echo "Stopping mediator..."
        ssh "${SERVICES_NODE}" ngcp-service mediator stop
        sleep 5
      else
        echo "Mediator not enabled."
      fi
      if [ "${RATEOMAT_RUN}" == "yes" ] ; then
        echo "Stopping rate-o-mat..."
        ssh "${SERVICES_NODE}" ngcp-service rateomat stop
        sleep 5
      else
        echo "Rate-o-mat not enabled."
      fi
    fi

  fi

  return 0
}


#----------------------------------------------------------------------
# Start mediator and rate-o-mat if the script is running on PRO or proxy node
start_services() {
  if [ "${NGCP_IS_PROXY}" == "yes" ] ; then

    if [ "${SERVICES_NODE}" == "${CURRENTNODE}" ] ; then
      if ngcp-check-active ; then
        echo -e "\nStarting mediator and rate-o-mat on local (${SERVICES_NODE}) node:"
        if [ "${RUN_MEDIATOR}" == "yes" ] ; then
          echo "Starting mediator..."
          ngcp-service mediator start
          sleep 5
        else
          echo "Mediator not enabled."
        fi
        if [ "${RATEOMAT_RUN}" == "yes" ] ; then
          echo "Starting rate-o-mat..."
          ngcp-service rateomat start
          sleep 5
        else
          echo "Rate-o-mat not enabled."
        fi
      fi
    else
      echo -e "\nStarting mediator and rate-o-mat on remote (${SERVICES_NODE}) node:"
      if [ "${RUN_MEDIATOR}" == "yes" ] ; then
        echo "Starting mediator..."
        ssh "${SERVICES_NODE}" ngcp-service mediator start
        sleep 5
      else
        echo "Mediator not enabled."
      fi
      if [ "${RATEOMAT_RUN}" == "yes" ] ; then
        echo "Starting rate-o-mat..."
        ssh "${SERVICES_NODE}" ngcp-service rateomat start
        sleep 5
      else
        echo "Rate-o-mat not enabled."
      fi
    fi

  fi

  return 0
}


#----------------------------------------------------------------------
# fix replication using the parameters configured before
fix_replication() {
  # stop mediator and rate-o-mat services if necessary
  stop_services

  echo -e "\nRestoring DB replication from ${MASTERNODE}:${MASTERPORT} to ${SLAVENODE}:${SLAVEPORT} (and fixing local ngcp.db_schema if necessary)..."

  ngcp-sync-db "${SCRIPT_OPT[@]}"

  while true ; do
    ERRORMASTER_text=$(ssh "${MASTERNODE}" ngcp-mariadb-replication-check -v 2>&1)
    ERRORMASTER_value=$?

    if [ -z "${FROMCENTRAL}" ] || [ "${FROMCENTRAL}" == "no" ] ; then
      ERRORSLAVE_text=$(ssh "${SLAVENODE}" ngcp-mariadb-replication-check -v 2>&1)
      ERRORSLAVE_value=$?
    else
      ERRORSLAVE_text_db01a=$(ssh "${SLAVENODE}" ngcp-mariadb-replication-check -v -l 2>&1)
      ERRORSLAVE_value_db01a=$?
      ERRORSLAVE_text_db01b=$(ssh "${SLAVENODE}" ngcp-mariadb-replication-check -v -L 2>&1)
      ERRORSLAVE_value_db01b=$?
      ERRORSLAVE_text="${ERRORSLAVE_text_db01a}\n${ERRORSLAVE_text_db01b}"
      ERRORSLAVE_value=$((ERRORSLAVE_value_db01a + ERRORSLAVE_value_db01b))
    fi

    if [ "${ERRORMASTER_value}" == "0" ] && [ "${ERRORSLAVE_value}" == "0" ] ; then
      echo -e "\nNo Replication errors detected. Proceeding..."
      break
    else
      echo -e "\nErrors detected:"
      echo "++++++++++++++++"
      echo "Error on ${MASTERNODE}: ${ERRORMASTER_text}"
      echo "----------------------------------"
      echo "Error on ${SLAVENODE}: ${ERRORSLAVE_text}"
      echo ""
      echo "Please fix the error or run the script again."
      echo "Do you want to check again the replication status (yes/no) ? "
      read -r check_again
      check_again="${check_again,,}"
      if [ "$check_again" == "no" ] ; then
        echo "Exiting."
        exit 0
      fi
    fi
  done

  # start mediator and rate-o-mat services if necessary
  start_services
}


#======================================================================


main
exit 0
