#!/bin/bash

set -e
set -u

# defaults
opt_adjust_for_low_performance=false
opt_adjust_for_high_performance=false
opt_skip_commit=false

CONFIG_YML='/etc/ngcp-config/config.yml'

usage() {
  echo "$0 - tool to adjust sip:provider configuration for low/high performance

  --help                Display this usage information
  --high-performance    Adjust configuration for system with normal/high performance
  --low-performance     Adjust configuration for system with low performance (e.g. VMs)
  --skip-commit         Do not commit ngcpcfg/etckeeper changes, just prepare configs
"
}

cmdline_handling() {
  local _cmdline_opts="help,high-performance,low-performance,skip-commit"
  local _opt_temp

  if ! _opt_temp=$(getopt --name "$0" -o +bvh --long $_cmdline_opts -- "$@"); then
    usage >&2
    exit 1
  fi

  if [ $# -lt 1 ]; then
    usage >&2
    exit 1
  fi

  eval set -- "$_opt_temp"

  while :; do
    case "$1" in
    --low-performance)
      opt_adjust_for_low_performance=true
      ;;
    --high-performance)
      opt_adjust_for_high_performance=true
      ;;
    --skip-commit)
      opt_skip_commit=true
      ;;
    --help)
      usage >&2
      exit 0
      ;;
    --)
      shift; break
      ;;
    *)
      echo "Internal getopt error! $1" >&2
      exit 1
      ;;
    esac
    shift
  done

  unset _cmdline_opts ; unset _opt_temp
}

set_high_performance() {
  bufferpoolsize=$(calculate_innodb_poolsize)
  if [ -z "$bufferpoolsize" ] ; then
    echo "Error retrieving MySQL bufferpoolsize"
    return 1
  fi

  kamailioshmmem=$(calculate_kamailio_shared_mem)
  if [ -z "$kamailioshmmem" ] ; then
    echo "Error retrieving kamailio proxy shared memory"
    return 1
  fi

  echo "Increasing default resource usage..."
  ngcpcfg set "${CONFIG_YML}" \
    "b2b.media_processor_threads='10'" \
    "b2b.session_processor_threads='10'" \
    "kamailio.lb.tcp_children='8'" \
    "kamailio.lb.udp_children='8'" \
    "kamailio.proxy.children='8'" \
    "kamailio.proxy.natping_processes='7'" \
    "kamailio.proxy.tcp_children='4'" \
    "kamailio.proxy.pkg_mem='192'" \
    "kamailio.proxy.presence.notifier_processes=1" \
    "kamailio.proxy.presence.notifier_poll_rate=3" \
    "kamailio.lb.shm_mem='128'" \
    "kamailio.lb.pkg_mem='16'" \
    "database.bufferpoolsize='${bufferpoolsize}'" \
    "kamailio.proxy.shm_mem='${kamailioshmmem}'" \
    "redis.maxmemory='0Gb'" \
    "cleanuptools.binlog_days='15'" \
    "www_admin.fastcgi_workers='10'" \
    "monitoring.threshold.mem_used_max='0.8'" \
    "monitoring.threshold.swap_free_min='0.5'" >/dev/null || return 1

  if [[ "${NGCP_TYPE}" == 'carrier' || "${NGCP_TYPE}" == 'sppro' ]]; then
    ngcpcfg set "${CONFIG_YML}" \
      "snmpagent.update_interval='5'" \
      "snmpagent.trees.collective_check='yes'" >/dev/null || return 1
  fi

  if ! "${opt_skip_commit}" ; then
    echo "Displaying the changes:"
    ngcpcfg diff | cat

    echo "Executing ngcpcfg commit..."
    ngcpcfg --no-db-sync commit "Adjust config.yml for high performance via ${0} (--no-db-sync)." >/dev/null || return 1

    echo "Executing etckeeper commit..."
    etckeeper commit "Adjust config.yml for high performance via ${0}." >/dev/null || true
  fi

  echo "Finished execution. Please execute 'ngcpcfg apply' to apply configuration."
}

set_low_performance() {
  echo "Decreasing default resource usage..."

  ngcpcfg set "${CONFIG_YML}" \
    "redis.maxmemory='50mb'" \
    "b2b.media_processor_threads='1'" \
    "b2b.session_processor_threads='1'" \
    "kamailio.lb.tcp_children='1'" \
    "kamailio.lb.udp_children='1'" \
    "kamailio.proxy.children='1'" \
    "kamailio.proxy.natping_processes='1'" \
    "kamailio.proxy.tcp_children='1'" \
    "kamailio.proxy.pkg_mem='96'" \
    "kamailio.proxy.presence.notifier_processes=1" \
    "kamailio.proxy.presence.notifier_poll_rate=1" \
    "kamailio.lb.shm_mem='64'" \
    "database.bufferpoolsize='64M'" \
    "cleanuptools.binlog_days='0'" \
    "www_admin.fastcgi_workers='2'" \
    "monitoring.threshold.mem_used_max='0.98'" \
    "monitoring.threshold.swap_free_min='0.02'" >/dev/null || return 1

  if [[ "${NGCP_TYPE}" == 'carrier' || "${NGCP_TYPE}" == 'sppro' ]]; then
    ngcpcfg set "${CONFIG_YML}" \
      "snmpagent.update_interval='60'" \
      "snmpagent.trees.collective_check='no'" >/dev/null || return 1
  fi

  if ! "${opt_skip_commit}" ; then
    echo "Displaying the changes:"
    ngcpcfg diff | cat

    echo "Executing ngcpcfg commit..."
    ngcpcfg --no-db-sync commit "Adjust config.yml for high performance via ${0} (--no-db-sync)." >/dev/null || return 1

    echo "Executing etckeeper commit..."
    etckeeper commit "Adjust config.yml for low performance via ${0}." >/dev/null || true
  fi

  echo "Finished execution. Please execute 'ngcpcfg apply' to apply configuration."
}

# based on installer.git/install/mysql.inc
calculate_innodb_poolsize() {
  local total_mem
  total_mem=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)

  if [ -z "$total_mem" ] ; then
    echo "Error: couldn't retrieve memory information" >&2
    return 1
  fi

  local innodb_buffer_pool_factor="0.5"
  local pool_size_mb
  pool_size_mb=$(echo | awk -v tm="${total_mem}" -v mf=${innodb_buffer_pool_factor} '{print int(tm*mf/1000)}')
  local pool_size_mb="${pool_size_mb}M"

  echo "$pool_size_mb"
}


calculate_kamailio_shared_mem() {
  local total_mem
  total_mem=$(awk '/^MemTotal:/ {print $2}' /proc/meminfo)

  if [ -z "$total_mem" ] ; then
    echo "Error: couldn't retrieve memory information" >&2
    return 1
  fi

  local kam_shm_factor="0.0625"
  local kam_shm_mb
  kam_shm_mb=$(echo | awk -v tm="${total_mem}" -v mf=${kam_shm_factor} '{print int(tm*mf/1000)}')
  
  echo "$kam_shm_mb"
}


cmdline_handling "$@"

if ! [ -r "$CONFIG_YML" ] ; then
  echo "Error: couldn't read /etc/ngcp-config/config.yml" >&2
  exit 1
fi

if [ $EUID -ne 0 ] ; then
  echo "Error: this script requires root permissions" >&2
  exit 1
fi


if [ -r /etc/default/ngcp-roles ] ; then
  # shellcheck disable=SC1091
  . /etc/default/ngcp-roles
else
  echo "Error: cannot load /etc/default/ngcp-roles" >&2
  exit 1
fi


if "$opt_adjust_for_low_performance" ; then
  set_low_performance || exit $?
elif "$opt_adjust_for_high_performance" ; then
  set_high_performance || exit $?
fi
