#!/bin/bash

# Скрипт помогает установить пакеты SoftWLC на один сервер
# Предварительно устанавливает Java, mysql-server, tomcat, curl, libcurl и прочие необходимые пакеты из зависимостей
# Затем последовательно устанавливает все нужные пакеты комплекса:
#
# eltex-oui-list           : Содержит список соответствий MAC-адресов и производителей оборудования
# eltex-axis               : Фреймворк для работы службы SOAP/XML (Apache Axis2)
# eltex-ems-db             : Разворачивает схему в БД MySQL для EMS
# eltex-radius-db          : Разворачивает схему в БД MySQL для RADIUS-сервера
# eltex-auth-service-db    : Разворачивает схему в БД MySQL для сервиса авторизации
# - eltex-portal-db        : Разворачивает схему в БД MySQL для портала авторизации (удалено с версии 1.18)
# eltex-auth-service       : Сервис аутентификации и авторизации SoftWLC
# eltex-ems                : Серверная и клиентская часть СУ EMS
# eltex-radius             : RADIUS-сервер
# eltex-radius-nbi         : Северный мост (northbound) для стыка SoftWLC с вышестоящими OSS/BSS
# eltex-ngw                : Сервис, предоставляющий возможность отправки уведомлений (СМС, звонков), используемый другими пакетами комплекса
# eltex-apb                : Сервис для взаимодействия точек доступа
# eltex-pcrf               : Служба управления политиками доступа (используется BRAS)
# eltex-logging-service    : Микросервис журналирования операций
# eltex-mercury            : Сервис по управлению Hotspot пользователями
# eltex-polly              : Сервис прохождения портальных опросов
# eltex-polly-db           : База данных сервиса прохождения портальных опросов
# eltex-portal             : Портал для авторизации клиентов WiFi в схеме 'Hotspot'
# eltex-portal-constructor : Web-приложение для создания и редактирования порталов для авторизации
# eltex-wifi-cab           : Личный кабинет оператора услуги Wi-Fi
# eltex-sorm2-replicator * : Служба для обогащения и пересылки radius acct в региональные съемники СОРМ-2
#                          : И для формирования ACCT отчетов СОРМ-3
# eltex-wifi-sa **         : Сервис-активатор ОТТ
# eltex-ott-mac-checker ** : Сервис проверки MAC-адреса на принадлежность к OTT домену
# eltex-ott-paul **        : Сервис ОТТ, генератор паролей
# eltex-bonnie ***         : Сервис статистика аккаунтинга из ClickHouse
# eltex-bonnie-db ***      : Разворачивает схему в БД ClickHouse для сервиса статистики
# eltex-disconnect-service : Сервис обеспечивает немедленное прерывание сессии пользователя
# eltex-doors              : Обеспечивает авторизацию пользователя/сервиса внутри ядра (внутреннее взаимод.)
# eltex-johnny             : REST API к Mercury для управления Enterprise и Hotspot пользователями
# eltex-bruce              : Сервис-планировщик задач, обеспечивает запуск задач по установленному расписанию
# eltex-jobs               : Сервис-исполнитель задач, выполняет задачи, запущенные eltex-bruce
#
# * - не устанавливаются по умолчанию, но могут быть установленны из репозитория.
# ** - не устанавливаются по умолчанию, но могут быть установлены с флагом WITH_OTT или отдельно из репо.
# *** - не устанавливаются по умолчанию, но могут быть установлены с флагом ClickHouse или отдельно из репо.

# Версия: SoftWLC 1.19, EMS 3.23
# Целевая ОС: xenial (ubuntu 16.04), bionic (ubuntu 18.04)
# Автор: Абаренов ВП
# ООО Предприятие Элтекс
# Новосибирск, 2021

# Модификаторы запуска скрипта:
# --skip          : пропустить установку системных пакетов. только установка пакетов из репозитория eltex.
#                 : рекомендуется использовать режим --skip при обновлении SWLC более ранних версий на U16.
# --clickhouse    : добавить установку БД clickhouse
# --ott           : добавить установку сервисов OTT

# Ответы для автоматической установки
# Измените при необходимости

# Имя пользователя администратора MySQL
export ANSWER_SOFTWLC_MYSQL_USER=root
# Пароль администратора MySQL
export ANSWER_SOFTWLC_MYSQL_PASSWORD=root
# Имя пользователя администратора SoftWLC
export ANSWER_AUTH_SERVICE_ADMIN_USER=admin
# Пароль администратора SoftWLC
export ANSWER_AUTH_SERVICE_ADMIN_PASSWORD=password
# Пароль служебного пользователя SoftWLC (softwlc_service)
export ANSWER_SOFTWLC_SERVICE_USER_PASSWORD=softwlc
# Корневой домен
export ANSWER_SOFTWLC_ROOT_DOMAIN=root
# Язык EMS по умолчанию: 1 - русский, 2 - английский
export ANSWER_EMS_LANG=1
# Максимальное количество ОЗУ, выделяемое EMS (в МБ)
export ANSWER_EMS_MAX_HEAP=1024
# Максимальное количество ОЗУ, выделяемое Tomcat (в МБ)
export ANSWER_TOMCAT_MAX_HEAP=1024
# Код создаваемого тарифа
export ANSWER_RADIUS_TARIFF_CODE=default
# Генерировать ли сертификат для сервера RADIUS
export ANSWER_NBI_MAKE_SERVER_CERTIFICATE=1
# Срок действия серверного сертификата RADIUS
export ANSWER_NBI_SERVER_CERTIFICATE_PERIOD=3650
# Пароль от закрытого ключа серверного сертификата RADIUS
export ANSWER_NBI_SERVER_CERTIFICATE_KEY=1234
# Ограничения пользователя javauser при многохостовой установке ClickHouse
export ANSWER_SOFTWLC_CLICKHOUSE_MULTIHOST=N

# Установить пакеты eltex-wifi-sa и eltex-ott-mac-checker
export WITH_OTT=0

# Не рекомендуется редактировать
export ANSWER_SOFTWLC_LOCAL=1
export ANSWER_EMS_REPLACE_CONF=1
export ANSWER_EMS_ACCESS_TYPE_DOMAIN=1
export ANSWER_RADIUS_MAKE_TARIFF=1
export ANSWER_RADIUS_TARIFF_PORTAL=1
export ANSWER_SOFTWLC_SERVICE_USER_LOGIN=softwlc_service
export ANSWER_RADIUS_DB_UPDATE_CRON=1
export ANSWER_SOFTWLC_SCHEDULE_BACKUP=Y

# Настройка автоматического ответа на интерактивные вопросы
export DEBIAN_FRONTEND="noninteractive"

red=`tput setaf 1`
green=`tput setaf 2`
reset=`tput sgr0`

# Public Eltex production repo
ELTEX_PUBLIC_REPO="http://archive.eltex-co.ru/wireless"
# Private (internal) repo
ELTEX_PRIVATE_REPO="http://lab3-repo.eltex.loc:2088"
# Переменная, которая является рабочей. Внутри скрипта работа идёт с ней в зависимости от параметров вызова скрипта
ELTEX_REPO=${ELTEX_PUBLIC_REPO}

## Установить ClickHouse и пакеты eltex-bonnie, eltex-bonnie-db
INSTALL_CLICKHOUSE=0

# Наименование программ (определяют путь в репозитории)
SOFTWLC_VERSION="softwlc-1.19"

REPO_GPG_KEY_ADDR="${ELTEX_REPO}/repo.gpg.key"
SOFTWLC_DISTRIBUTION="$SOFTWLC_VERSION"     # * параметр зависит от версии ubuntu (будет переопределён в коде)
SOFTWLC_REPO_SOURCES="deb [arch=amd64] $ELTEX_REPO $SOFTWLC_VERSION main"

DHCPD_HELPER="$(dirname `which $0`)/dhcpd-helper.sh"

NGINX_CONFIG_FILE="softwlc_1.19_nginx.conf"
# переменная для пропуска установки пакетов linux, java и т.д. (т.е. только установка/обновление Eltex-пакетов из репо)
SKIP_LINUX_DEB=0

# Вендор JVM
JAVA_VENDOR="openjdk"
TOMCAT_PACKET_NAME="tomcat7"                       # по умолчанию ставить tomcat7, в более поздних (>= bionic) ставить 8

MONGO_DBS="admin
        local
        ott
        pcrf
        wifi-customer-cab"

MONGO_EXPORT_PATH="/tmp/mongoexport/"

# Массив внешних IP сервера (весь ifconfig, кроме 127.0.0.1)
EXTERNAL_IPS=()

# Прервать установку при ошибках
set -e

echo "${green}Installation started for $SOFTWLC_VERSION, from $ELTEX_REPO${reset}"

# Метод удаляет файл с Элтекс репо, т.к. при недоступности репо скрипт не
# может выполнить ни одну из функций
clean_eltex_repo() {
    # удалить старый репозиторий (ems, softwlc), если он есть
    if [[ -f "/etc/apt/sources.list.d/eltex.list" ]]; then
        rm /etc/apt/sources.list.d/eltex.list
    fi
}

check_memory() {
  ram=$(grep MemTotal /proc/meminfo | awk '{printf "%d", $2 / 1000}')

    if [[ ${INSTALL_CLICKHOUSE} == 1 ]]; then
      if [[ $ram -lt 8000 ]]; then
        echo "${red}You have $ram MB of RAM. You need 8 GB of RAM and 10 GB of free hard disk space, installation aborted!${reset}"
        exit 1
      fi
    else
      if [[ $ram -lt 6000 ]]; then
        echo "${red}You have $ram MB of RAM. You need 6 GB of RAM and 10 GB of free hard disk space, installation aborted!${reset}"
        exit 1
      fi
    fi

  free_space=$(df / | grep / | awk '{printf "%d", $4 / 1000}')

  if [[ $free_space -lt 10000 ]]; then
    echo "${red}You have $free_space MB of free hard disk space. 10 GB required for installation. Installation aborted!${reset}"
    exit 1
  fi
}

update_repo_related_vars() {
    REPO_GPG_KEY_ADDR="${ELTEX_REPO}/repo.gpg.key"
    SOFTWLC_REPO_SOURCES="deb [arch=amd64] $ELTEX_REPO $SOFTWLC_VERSION main"
}

# проверить наличие обязательного файла (без него не будет настроен nginx, а значит не заработает половина сервисов)
check_nginx_config() {
    if [[ -f "$NGINX_CONFIG_FILE" ]]
    then
        echo "File '$NGINX_CONFIG_FILE' found."
        FILESIZE=$(stat -c%s "$NGINX_CONFIG_FILE")
        if [ $FILESIZE -gt 0 ];then
            echo "Size of $NGINX_CONFIG_FILE = $FILESIZE bytes."
        else
            echo "$(tput setaf 1)File '$NGINX_CONFIG_FILE' is empty, installation aborted!$(tput sgr 0)"
            exit -1
        fi
    else
        echo "$(tput setaf 1)File '$NGINX_CONFIG_FILE' not found, installation aborted!$(tput sgr 0)"
        exit -1
    fi
}

set_silent_mode() {
    # mysql root password settings (default: login=root, password=root)
    sudo debconf-set-selections <<< "mysql-server mysql-server/root_password password $ANSWER_SOFTWLC_MYSQL_PASSWORD"
    sudo debconf-set-selections <<< "mysql-server mysql-server/root_password_again password $ANSWER_SOFTWLC_MYSQL_PASSWORD"
    # rsyslog-mysql login@password settings (default: login=root, password=root)
    echo "rsyslog-mysql   rsyslog-mysql/dbconfig-install  boolean true" | debconf-set-selections
    echo "rsyslog-mysql   rsyslog-mysql/mysql/app-pass    password $ANSWER_SOFTWLC_MYSQL_PASSWORD" | debconf-set-selections
    echo "rsyslog-mysql   rsyslog-mysql/app-password-confirm      password $ANSWER_SOFTWLC_MYSQL_PASSWORD" | debconf-set-selections
    echo "rsyslog-mysql   rsyslog-mysql/password-confirm  password $ANSWER_SOFTWLC_MYSQL_PASSWORD" | debconf-set-selections
    echo "rsyslog-mysql   rsyslog-mysql/mysql/admin-pass  password $ANSWER_SOFTWLC_MYSQL_PASSWORD" | debconf-set-selections
    echo "rsyslog-mysql   rsyslog-mysql/remote/port       string " | debconf-set-selections
}


install() {
    apt-get --yes install "$@"
}


stop() {
    # add '|| true' - to ignore error
	service "$@" stop || true
}

restart() {
	service "$@" restart
}

start() {
	service "$@" start
}

reload() {
	service "$@" reload || true
}

update() {
    apt-get -y update || true
}

# Контроль открытого порта (без контроля службы)
# Вызов функции: check_port "8080" result_var
# В результат будет помещён 0 - OK (порт открыт) или 1 - Ошибка (порта нет)
function check_port() {
    local  __resultvar=$2
    local  myresult='0'
    if [[ `netstat -pna | grep ":$1"` ]]; then
        echo "${green}Checking port '$1' - passed${reset}"
        myresult='0'
    else
        echo "${red}Checking port '$1' - error${reset}"
        myresult='1'
    fi
    eval ${__resultvar}="'$myresult'"
}

# Контроль открытого порта для определённой службы в режиме TCP (+ контроль LISTEN)
# Пример вызова функции: check_port_service_tcp "8080" "nginx" "nginx" result_var
# Пример вызова функции: check_port_service_tcp "8080" "java" "tomcat" result_var
# $1 - номер порта (строкой);
# $2 - название сервиса (java - для всех java приложений);
# $3 - описание сервиса, например, 'tomcat' или 'Captive Portal' для Java приложения;
# $4 - В результат будет помещена строка: "0" - это OK (порт открыт) или "1" - это ошибка (порта нет)
function check_port_service_tcp() {
    local __resultvar="$4"
    local myresult='0'
    local port=":$1"
    local service="$2"
    local service_descr="$3"
    local variable=$(ss -tnlp | awk '{if ($1 == "LISTEN" && $4 ~ "'"$port"'" && ($6 ~ /'"$service"'/ || $6 ~ /docker-proxy/)) print "passed"}')
    if [[ $variable =~ "passed" ]]; then
        echo "${green}Checking tcp port '$1' for application '$2' ($service_descr) - passed${reset}"
        myresult='0'
    else
        echo "${red}Checking tcp port '$1' for application '$2' ($service_descr) - error${reset}"
        myresult='1'
    fi
    eval ${__resultvar}="'$myresult'"
}

# Контроль открытого порта для определённой службы в режиме UDP (нет LISTEN)
# Пример вызова функции: check_port_service_udp "8080" "nginx" "nginx" result_var
# Пример вызова функции: check_port_service_udp "8080" "java" "tomcat" result_var
# $1 - номер порта (строкой);
# $2 - название сервиса (java - для всех java приложений);
# $3 - описание сервиса, например, 'tomcat' или 'Captive Portal' для Java приложения;
# $4 - В результат будет помещена строка: "0" - это OK (порт открыт) или "1" - это ошибка (порта нет)
function check_port_service_udp() {
    local __resultvar="$4"
    local myresult=0
    local port=":$1"
    local service="$2"
    local service_descr="$3"
    local variable=$(ss -unlp | awk '{if (($1 == "UNCONN" || $1 == "ESTAB") && $4 ~ "'"$port"'" && ($6 ~ /'"$service"'/ || $6 ~ /docker-proxy/)) print "passed"}')
    if [[ $variable =~ "passed" ]]; then
        echo "${green}Checking udp port '$1' for application '$2' ($service_descr) - passed${reset}"
        myresult="0"
    else
        echo "${red}Checking udp port '$1' for application '$2' ($service_descr) - error${reset}"
        myresult="1"
    fi
    eval ${__resultvar}="'$myresult'"
}

# Функция для финальной проверки всех портов однохостовой инсталляции
# Считает количество фатальных ошибок (не все порты критичные)
# Если количество фатальных ошибок больше нуля, то после отчёта скрипт прервётся и выйдет с "-1"
function main_ports_test() {
    local FATAL=0
    echo ""
    echo "Start TCP/UDP port checking for all services.."

    # == databases ==
    check_port_service_tcp "3306" "mysqld" "Server MySQL" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "27017" "mongo" "MongoDB server" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # == EMS ==
    check_port_service_tcp "9310" "java" "EMS-server Applet API " var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_udp "162" "java" "EMS server SNMP API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # == tomcat ==
    check_port_service_tcp "8081" "java" "tomcat (LK B2B, NBI, EMS applet)" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # == nginx ==
    check_port_service_tcp "8080" "nginx" "Nginx proxy server" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # == Portal, Portal Constructor, NGW==
    check_port_service_tcp "9000" "java" "Captive Portal, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "9001" "java" "Portal Constructor, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "8040" "java" "eltex-notification-gw, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "8090" "java" "eltex-apb, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "9099" "java" "eltex-logging-service, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "9099" "java" "eltex-mercury service, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # polly
    check_port_service_tcp "9088" "java" "eltex-polly service GRPC API, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "9089" "java" "eltex-polly service HTTP API, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # doors
    check_port_service_tcp "9097" "java" "eltex-doors service HTTP API, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # johnny
    check_port_service_tcp "9100" "java" "eltex-johnny service HTTP API, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # eltex-disconnect-service
    check_port_service_tcp "9096" "java" "eltex-disconnect service service HTTP API, Portal Group" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi


    # == PCRF ==
    check_port_service_tcp "7070" "java" "PCRF monitoring API" var
    check_port_service_tcp "7080" "java" "PCRF RADIUS API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi
    check_port_service_tcp "5701" "java" "PCRF Hazelcast API" var
    check_port_service_udp "1813" "java" "PCRF, RADIUS accounting API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # eltex-bruce
    check_port_service_tcp "8008" "java" "eltex-bruce service HTTPS API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # eltex-jobs
    check_port_service_tcp "9696" "java" "eltex-jobs service HTTPS API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    # == RADIUS, Auth Service ==
    check_port_service_udp "1812" "eltex-radius" "RADIUS, auth API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_udp "21812" "eltex-radius" "Eltex Auth Service, auth API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi
    check_port_service_udp "21813" "eltex-radius" "Eltex Auth Service, accounting API" var

    # == Other ==
    check_port_service_udp "514" "syslog" "Linux syslog server" var
    check_port_service_udp "69" "tftp" "Linux TFTP server" var

    echo ""
    # Финальный контроль фатальных ошибок
    if [ $FATAL != 0 ]; then
        echo "${red}Found $FATAL errors, script aborted!${reset}"
        exit -1
    else
        echo "${green}> Main core ports are tested successfully!${reset}"
    fi
    echo ""
}

# Функция для контроля портов работы ядра в режиме OTT
function ott_ports_test() {
    local FATAL=0
    echo ""
    echo "Start TCP/UDP port checking for OTT services.."

    check_port_service_tcp "8088" "java" "eltex-ott-mac-checker, OTT" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "8098" "java" "eltex-paul, password generator, OTT" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "8043" "java" "eltex-wifi-sa, service activator HTTPS API, OTT" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    echo ""
    # Финальный контроль фатальных ошибок
    if [ $FATAL != 0 ]; then
        echo "${red}Found $FATAL errors, script aborted!${reset}"
        exit -1
    else
        echo "${green}> OTT ports are tested successfully!${reset}"
    fi
    echo ""
}

# Функция для контроля портов работы ядра в режиме Clickhouse
function clickhouse_ports_test() {
    local FATAL=0
    echo ""
    echo "Start TCP/UDP port checking for Clickhouse database and services.."

    # == Clickhouse ==
    check_port_service_tcp "9003" "clickhouse" "Clickhouse client API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "9009" "clickhouse" "Clickhouse inter serever API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "8123" "clickhouse" "Clickhouse HTTP API" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    check_port_service_tcp "9070" "eltex-bonnie" "Bonnie GRPC API, Clickhouse" var
    if [[ "$var" != "0" ]]; then
        FATAL=$((FATAL+1))
    fi

    echo ""
    # Финальный контроль фатальных ошибок
    if [ $FATAL != 0 ]; then
        echo "${red}Found $FATAL errors, script aborted!${reset}"
        exit -1
    else
        echo "${green}> Clickhouse ports are tested successfully!${reset}"
    fi
    echo ""
}

# Заполнить массив EXTERNAL_IPS внешними IP сервера (весь ifconfig, кроме 127.0.0.1)
find_external_ips() {
    local ifconfig="$(ifconfig | grep -Po '(?<=inet\s)[^\s]*')"
    for address in ${ifconfig}; do
        if [[ ${address} != "127.0.0.1" ]]; then
            EXTERNAL_IPS+=($address)
        fi
    done
}

# Запросить у пользователя внешний IP из EXTERNAL_IPS.
# В $1 функция возвращает значение IP (не индекс)
function select_ip() {
    local __resultvar=$1
    while [[ 1 ]]; do
        read ans
        if [[ 0 < ${ans} && ${ans} < ${#EXTERNAL_IPS[@]}+1 ]]; then
            break
        else
            echo "Wrong IP number. Try again"
        fi
    done
    eval ${__resultvar}="${EXTERNAL_IPS[ans-1]}"
}

# Узнать внешние IP сервера и, если их несколько, предложить пользователю выбор.
# В $1 функция возвращает окончательное значение внешнего IP
function detect_external_ip() {
    find_external_ips
    local __resultvar=$1
    case ${#EXTERNAL_IPS[@]} in
        0)
            echo "No external IP addresses have been detected"
            host="127.0.0.1"
            ;;
        1)
            echo "External IP address has been detected"
            host=${EXTERNAL_IPS[0]}
            ;;
        *)
            echo "${yellow}Several external IPs have been detected:"
            for index in "${!EXTERNAL_IPS[@]}"
            do
                echo "$(($index + 1)). ${EXTERNAL_IPS[index]}"
            done
            echo "Which one will be used to open the portal constructor and the customer cabinet in a browser?${reset}"
            select_ip host
    esac
    eval ${__resultvar}="${host}"
}

# Перезаписывает файловые лимиты для службы mysql
function replace_open_files_for_mysql() {
  local DIR="/etc/systemd/system/mysql.service.d"
  local FILE_OVERRIDE="$DIR/override.conf"
  if [ -f "$FILE_OVERRIDE" ]; then
    rm "$FILE_OVERRIDE"
  fi

  if [ ! -d "$DIR" ]; then
    mkdir -p "$DIR"
  fi

  echo "[Service]" >"$FILE_OVERRIDE"
  echo "LimitNOFILE=65535" >>"$FILE_OVERRIDE"
  echo "LimitNOFILESoft=65535" >>"$FILE_OVERRIDE"
  echo "File '$FILE_OVERRIDE' replaced with new configuration"
  systemctl daemon-reload
  restart mysql
}

# Самое первое - это запрет работы не от root
if [[ `id -u` -ne 0 ]]; then
    echo "${red}This script can only be run as root${reset}"
    exit 1
fi


if [[ -n "$1" ]]; then
    for i in "$@" ; do
        # Определить repo: public | internal
        if [[ ${i} == "--public" ]] ; then
            ELTEX_REPO=${ELTEX_PUBLIC_REPO}
            update_repo_related_vars
            break
        fi

        if [[ ${i} == "--private" ]] ; then
            ELTEX_REPO=${ELTEX_PRIVATE_REPO}
            update_repo_related_vars
            break
        fi

        # Выставить режим пропуска инсталляции системных пакетов
        if [[ ${i} == "--skip" ]] ; then
            SKIP_LINUX_DEB=1
            echo "${green}Skipping installation of system packages${reset}"
            break
        fi

        ## Set the variable INSTALL_CLICKHOUSE
        if [[ ${i} == "--clickhouse" ]] ; then
            INSTALL_CLICKHOUSE=1
        fi

        ## Set the variable OTT
        if [[ ${i} == "--ott" ]] ; then
            WITH_OTT=1
        fi

    done
fi


# узнать кодовое имя дистрибутива ubuntu вперёд всех операций
DISTRIB_CODENAME=
source /etc/lsb-release

echo "${green}Ubuntu distrib code name: $DISTRIB_CODENAME${reset}"

if [[ ! (${DISTRIB_CODENAME} == "xenial" || ${DISTRIB_CODENAME} == "bionic") ]]; then
    echo "${red}Only ubuntu 16.04 (xenial) and 18.04 (bionic) is supported.${reset}"
    exit 1
fi


# проверить разрядность системы и отказаться работать, если не x64
DISTRIB_PLATFORM=`/bin/uname -m`
echo "Platform : $DISTRIB_PLATFORM"

if [[ ${DISTRIB_PLATFORM} != "x86_64" ]] ; then
    echo "${red}Platform is not 'x86_64', script aborted!${reset}"
    exit -1
fi


# вывести в консоль репозиторий после проверки флага
echo "${green}Repository: $ELTEX_REPO ${reset}"

echo "${green}Java vendor: $JAVA_VENDOR${reset}"


# выполнение 'clean_eltex_repo' ДО любых действий с утилитой apt, т.к. переключение repo
# может приводить к недоступности repo ('private' vs 'public') и скрипт прервётся на apt update
clean_eltex_repo

check_memory


# получить конфигурацию nginx соотв. версии
wget ${ELTEX_REPO}/nginx/conf/${NGINX_CONFIG_FILE} -O ${NGINX_CONFIG_FILE} || true

check_nginx_config

# Путь репозитория переопределяется в зависимости от имени дистрибутива Ubuntu
SOFTWLC_DISTRIBUTION="$SOFTWLC_VERSION-$DISTRIB_CODENAME"

# установить (обновить) программу работы с репозиторием add-apt-repository (т.к. в некоторых системах она не присутствует)
install software-properties-common

if [[ ${DISTRIB_CODENAME} != "bionic" ]]; then
    # обновить репозиторий (перед инсталляцией gnupg-curl, иначе он недоступен!)
    apt-get update || true

    # установка пакета 'gnupg-curl', без которого в некоторых системах невозможно выкачать и проверить 'keyserver'
    install gnupg-curl
fi


# добавить репозиторий Eltex в список источников apt
echo "deb [arch=amd64] $ELTEX_REPO $SOFTWLC_DISTRIBUTION main" >> /etc/apt/sources.list.d/eltex.list

wget -O - ${REPO_GPG_KEY_ADDR} | sudo apt-key add -

# Ставим всегда самый новый nginx с родного репо проекта (иначе несовместимость по конфигам старых версий)
wget http://nginx.org/keys/nginx_signing.key
apt-key add nginx_signing.key

echo "deb http://nginx.org/packages/ubuntu/ $DISTRIB_CODENAME nginx" > /etc/apt/sources.list.d/nginx.list


# Режим "пропустить инсталляцию системных пакетов"
if [[ ! ${SKIP_LINUX_DEB} == "1" ]] ; then
    # [section JVM]
    # если архивная версия Ubuntu, то подключить другой repo
    if [[ ${DISTRIB_CODENAME} == "trusty" ]]; then
        echo "${green}Ubuntu 14.04 (trusty) detected. Add other openjdk repo..${reset}"
        add-apt-repository -y ppa:openjdk-r/ppa
    fi

    # Добавить новый доверенный ключ на репозиторий mysql 
    apt-key adv --keyserver keyserver.ubuntu.com --recv-keys B7B3B788A8D3785C

    # обновить репозиторий
    update

    # Заранее задать ответы на вопросы инсталлятора о паролях mysql и прочее
    set_silent_mode

    # провести инсталляцию пакета openjdk
    install openjdk-8-jdk
    # прописать в системе использование только что установленного пакета
    update-java-alternatives -s java-1.8.0-openjdk-amd64

    # Обязательное создание линка ДО инсталляции Tomcat
    # иначе процесс для Tomcat вывалится с ошибкой 'Not found JAVA_HOME' и вся установка прервётся.
    # Обнаружено в Ubuntu16 (xenial), в старой Ubuntu14 (trusty) всё проходило нормально.
    if [[ ! -e /usr/lib/jvm/default-java ]]; then
        ln -s /usr/lib/jvm/java-8-openjdk-amd64 /usr/lib/jvm/default-java
    fi

    if [[ "$DISTRIB_CODENAME" == "bionic" ]]; then
        TOMCAT_PACKET_NAME="tomcat8"
    fi

    # установить Tomcat
    install ${TOMCAT_PACKET_NAME}

    # Установить максимальный размер heap для Tomcat
    sed -i "s/-Xmx[0-9]\+[a-zA-Z]/-Xmx${ANSWER_TOMCAT_MAX_HEAP}m/" /etc/default/${TOMCAT_PACKET_NAME}

    # Добавить джава опцию, изменяющую рандом файл на urandom
    if ! grep "^[^#].*-Djava\.security\.egd=file:/dev/\./urandom\b" /etc/default/${TOMCAT_PACKET_NAME} &> /dev/null; then
        echo "JAVA_OPTS=\"\${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom\"" >> /etc/default/${TOMCAT_PACKET_NAME}
    fi

    # Принудительное использование openjdk в Tomcat
    echo "JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64" >> /etc/default/${TOMCAT_PACKET_NAME}

    # установить прочие пакеты, которые прописаны в зависимостях пакета eltex-ems
    install expect daemon psmisc mysql-server mysql-client ntp tftp-hpa tftpd-hpa snmpd snmp rsyslog curl libpcap0.8-dev

    # Пакеты для работы видео на портале и в конструкторе. Метапакет ffmpeg.
    install ffmpeg
    # некоторые дистрибутивы (desktop) могут не содержать net-tools:netstat
    install net-tools

    if [[ "$DISTRIB_CODENAME" == "bionic" ]]; then
        install libcurl4
    else
        install libcurl3
    fi

    # прописать принудительно выключение ssl сервиса mysql для всех целевых ОС
    MYSQL_CFG_FILE=/etc/mysql/mysql.conf.d/mysqld.cnf
    if [[ ! -f "$MYSQL_CFG_FILE" ]]; then
      echo "file not exists '$MYSQL_CFG_FILE'"
    else
      # Если файл есть, то проверить что в конфиге ssl ещё не выключен
      if [[ ! `egrep "^[^#;]" $MYSQL_CFG_FILE | egrep "ssl=0"` ]]; then
        echo -en '\nssl=0\n' >> $MYSQL_CFG_FILE
        echo "Modified file '$MYSQL_CFG_FILE', restarting service mysql"
        service mysql restart
      fi
    fi

    # переписываем лимиты для сервиса mysql, иначе rsyslog-mysql с пагинацией не работает на различных ОС
    replace_open_files_for_mysql

    # rsyslog-mysql устанавливается только после окончания установки mysql-server
    # иначе попытка его конфигурирования провалится
    install rsyslog-mysql

    # установить MongoDB
    install mongodb-org
    # mongodb-org не стартует автоматически после инсталляции, нужно руками обеспечить его старт, чтобы остальное корректно установилось
    case "$DISTRIB_CODENAME" in
      "trusty")
        # update-rc.d mongod enable
        ;;
      "xenial")
        systemctl enable mongod.service
        ;;
      "bionic")
        systemctl enable mongod.service
        ;;
      *)
        echo "Unknown Ubuntu codename. Script aborted!"
        exit -1
        ;; 
    esac

    service mongod restart
else

    update

fi


## Install ClickHouse
if [[ ${INSTALL_CLICKHOUSE} -eq 1 ]]; then

    echo "Install ClickHouse"
    echo "deb http://repo.yandex.ru/clickhouse/deb/stable/ main/" > /etc/apt/sources.list.d/clickhouse.list
    install dirmngr    # optional
    apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4    # optional
    update
    install clickhouse-client clickhouse-server

    ## Install bonnie-db with ClickHouse configuration files
    echo "Install eltex-bonnie-db"
    install eltex-bonnie-db

    ## Start clickhouse-server
    echo "Start clickhouse-server.."
    restart clickhouse-server

    ## Health check
    getresult=$(systemctl is-active clickhouse-server.service)

    if [[ ${getresult} = "active" ]]; then
        echo "${green}. done${reset}"
    elif [[ ${getresult} = "inactive" ]]; then
        echo "${red}. fail. Look the logs in /var/log/clickhouse-server${reset}"
        exit 1
    fi
fi


PACKAGES="eltex-oui-list
        eltex-axis
        eltex-ems-db
        eltex-radius-db
        eltex-auth-service-db
        eltex-polly-db
        eltex-ems
        eltex-radius
        eltex-radius-nbi
        eltex-auth-service
        eltex-ngw
        eltex-apb
        eltex-pcrf
        eltex-logging-service
        eltex-mercury
        eltex-polly
        eltex-portal
        eltex-portal-constructor
        eltex-wifi-cab
        eltex-disconnect-service
        eltex-johnny
        eltex-doors
        eltex-bruce
        eltex-jobs"

if [[ ${WITH_OTT} == 1 ]]; then
  PACKAGES="$PACKAGES
        eltex-wifi-sa
        eltex-ott-paul
        eltex-ott-mac-checker"
fi

if [[ ${INSTALL_CLICKHOUSE} == 1 ]]; then
  PACKAGES="$PACKAGES
        eltex-bonnie"
fi

# Последовательная установка пакетов
for package in ${PACKAGES}; do
    echo
    echo "*"
    echo "* Installing $package ..."
    echo "*"
    echo

    install ${package}

    case "$package" in
        eltex-radius-nbi)
            # Установить серверный сертификат в eltex-radius
            /var/lib/eltex-radius-nbi/setup_er_eap.sh
        ;;
    esac
done

if [[ -x "$DHCPD_HELPER" ]]; then
    echo -n "Install and configure ISC DHCP server? [y/N] "
    read ans
    if [[ "$ans" == [yY] ]] ; then
        install isc-dhcp-server
        ${DHCPD_HELPER}
    fi
fi

# Модификации tomcat

TOMCAT_BASE=
TOMCAT_SERVICE=
source "/var/lib/eltex-ems/tomcat-consts"

stop ${TOMCAT_SERVICE}

# Добавить RemoteIpValve в server.xml

VALVE="        <!-- #96184 forward remote ip for nginx -->\n\
        <Valve className=\\\"org.apache.catalina.valves.RemoteIpValve\\\"\n\
           remoteIpHeader=\\\"X-Forwarded-For\\\"\n\
           internalProxies=\\\"127\\\\.0\\\\.0\\\\.1\\\"\n\
           requestAttributesEnabled=\\\"true\\\"/>\n"

AWK="BEGIN {
print \"Input file:\", ARGV[1];
OUTFILE = ARGV[1] \"_\";
print \"Temporary output file:\", OUTFILE;
ALREADY=0;
}
/org\.apache\.catalina\.valves\.RemoteIpValve/ {
ALREADY=1;
exit;
}
/<\/Host>/ {
print \"$VALVE\" > OUTFILE;
}
{
print > OUTFILE;
}
END {
if (ALREADY==0) {
print \"Replace original file '\" ARGV[1] \"' content\";
system(\"cat \" OUTFILE \" > \" ARGV[1]);
}
print \"Remove temporary file '\" OUTFILE \"'\";
system(\"rm \" OUTFILE);
}
"

awk "$AWK" ${TOMCAT_BASE}/conf/server.xml

# Изменить порт tomcat на 8081

PORT8081="    <Connector port=\\\"8081\\\" protocol=\\\"HTTP/1.1\\\""

AWK8081="BEGIN {
print \"Input file:\", ARGV[1];
OUTFILE = ARGV[1] \"_\";
print \"Temporary output file:\", OUTFILE;
ALREADY=0;
}
/Connector port=\"8081\"/ {
ALREADY=1;
exit;
}
/Connector port=\"8080\"/ {
print \"$PORT8081\" > OUTFILE;
next;
}
{
print > OUTFILE;
}
END {
if (ALREADY==0) {
print \"Replace original file '\" ARGV[1] \"' content\";
system(\"cat \" OUTFILE \" > \" ARGV[1]);
}
print \"Remove temporary file '\" OUTFILE \"'\";
system(\"rm \" OUTFILE);
}
"

awk "$AWK8081" ${TOMCAT_BASE}/conf/server.xml

# Установка Nginx

install nginx
cp ${NGINX_CONFIG_FILE} /etc/nginx/conf.d/softwlc.conf


# Записать wifi-cab secret в параметры EMS, чтобы API работало корректно:
#
#$ sudo cat /etc/eltex-wifi-cab/local_secret into eltex_ems.PARAMS
#+----------------+----------------+----------------------------------+
#| param1         | param2         | value                            |
#+----------------+----------------+----------------------------------+
#| wirelessCommon | wificab.secret | 12b3dc9c63c8c75e307855398ac4fbaf |
#+----------------+----------------+----------------------------------+

CAB_KEY="unknown"
CAB_KEY_FILE="/etc/eltex-wifi-cab/local_secret"

while read -r line; do
    CAB_KEY="$line"
    #echo "secret : $key"
done < "$CAB_KEY_FILE"

mysql -ujavauser -pjavapassword -e "INSERT INTO eltex_ems.PARAMS (id, param1, param2, value) \
 VALUES(1, 'wirelessCommon', 'wificab.secret', '$CAB_KEY') \
 ON DUPLICATE KEY UPDATE param1='wirelessCommon', param2='wificab.secret', value='$CAB_KEY';"

# Возьмём из ifconfig внешний IP, а если их несколько, то спросим у пользователя, какой прописать в настройки
echo "Setting portal constructor and customer cabinet link addresses.."
detect_external_ip external_ip
echo "Server external IP is $external_ip"
echo

mongo_command="db.config.update({}, {\$set: {\"portal.url\": \"http://$external_ip:9001/epadmin/\"}})"
mongo wifi-customer-cab --eval "$mongo_command"
echo "Portal constructor link in customer cabinet created"
echo

mysql_command="UPDATE ELTEX_PORTAL.properties SET value = \"$external_ip\" WHERE group_id = 7 AND name = \"host\";"
mysql -ujavauser -pjavapassword -e "$mysql_command"
echo "Customer cabinet link in portal constructor created"

echo "Creating database user and access grants for eltex-ngw"
eltex-ngw create-db-user -u "$ANSWER_SOFTWLC_MYSQL_USER" -p "$ANSWER_SOFTWLC_MYSQL_PASSWORD"


echo "Restarting all eltex services.."
# Перезапустить сервисы
restart ${TOMCAT_SERVICE}
restart nginx
restart eltex-radius
restart eltex-auth-service
restart eltex-pcrf
restart eltex-apb
restart eltex-ngw
# EMS (stop, start)
stop eltex-ems
start eltex-ems
# main other
restart eltex-polly
restart eltex-mercury
restart eltex-logging-service
restart eltex-portal
restart eltex-portal-constructor
restart eltex-doors
restart eltex-bruce
restart eltex-jobs

if [[ ${INSTALL_CLICKHOUSE} -eq 1 ]]; then
    restart eltex-bonnie
fi

if [[ ${WITH_OTT} == 1 ]]; then
    restart eltex-wifi-sa
    restart eltex-ott-paul
    restart eltex-ott-mac-checker
fi

# проверить открытые порты
echo "Waiting 120 seconds.."
echo -ne '##                        (10%)\r'
sleep 12
echo -ne '####                      (20%)\r'
sleep 12
echo -ne '######                    (30%)\r'
sleep 12
echo -ne '########                  (40%)\r'
sleep 12
echo -ne '##########                (50%)\r'
sleep 12
echo -ne '############              (60%)\r'
sleep 12
echo -ne '################          (70%)\r'
sleep 12
echo -ne '##################        (80%)\r'
sleep 12
echo -ne '####################      (90%)\r'
sleep 12
echo -ne '######################    (100%)\r'
echo -ne '\n'

echo "Check EMS port (60 seconds for retry).."
CHECK_COUNT=60
PORT_9310_PASSED="1"
for i in $(seq 1 ${CHECK_COUNT}); do
    check_port "9310" check_port_result
    if [[ "$check_port_result" != "0" ]]; then
        sleep 1
    else
        PORT_9310_PASSED="0"
        break
    fi
done

#Если все циклы проверки прошли, а порт 9310 так и не открылся, значит беда, выходим отсюда
if [[ "$PORT_9310_PASSED" != "0" ]] ; then
    echo "${red}Packet eltex-ems out of service (port 9310 not opened)${reset}"
    exit -1
fi

# тестирование всех портов комплекса, если один из жизненно важных портов не будет открыт
# будет выход внутри функции: exit -1

# Ждём ещё 10 секунд, т.к. между инициализацией порта 9310 и SNMP-engine проходит долгое время внутри EMS
echo "Waiting 10 seconds.."
sleep 10

main_ports_test

if [[ ${WITH_OTT} == 1 ]]; then
    ott_ports_test
fi

if [[ ${INSTALL_CLICKHOUSE} == 1 ]]; then
    clickhouse_ports_test
fi

echo "Checking EMS internal NBI"
if [[ `curl "localhost:8080/northbound/getVersion"` ]]; then
    echo "${green}Checking EMS.NBI on 'localhost' - passed${reset}"
else
    echo "${red}Checking EMS.NBI on 'localhost' - error${reset}"
    exit -1
fi

echo "Checking mongodb server and database.."
if [[ `mongo pcrf --eval "printjson(db.getCollectionNames())"` ]]; then
    echo "${green}Checking mongodb database PCRF - passed${reset}"
else
    echo "${red}Checking mongodb database PCRF - error${reset}"
    exit -1
fi
if [[ `mongo wifi-customer-cab --eval "printjson(db.getCollectionNames())"` ]]; then
    echo "${green}Checking mongodb database wifi-customer-cab - passed${reset}"
else
    echo "${red}Checking mongodb database wifi-customer-cab - error${reset}"
    exit -1
fi

# Всё
echo ""
echo "Installation of Eltex SoftWLC finished successfully."
echo ""

echo "URLs of SoftWLC components:

Eltex.EMS GUI: http://$external_ip:8080/ems/jws
    login: admin
    password: <empty>

Portal constructor: http://$external_ip:8080/epadmin
    login: $ANSWER_AUTH_SERVICE_ADMIN_USER
    password: $ANSWER_AUTH_SERVICE_ADMIN_PASSWORD

Wi-Fi customer cabinet (B2B): http://$external_ip:8080/wifi-cab
    login: $ANSWER_AUTH_SERVICE_ADMIN_USER
    password: $ANSWER_AUTH_SERVICE_ADMIN_PASSWORD"

exit 0
