#!/bin/sh
# Copyright (c) 2017-2021 by 4PSA
# All rights reserved

# This script installs or update VoipNow on supported OS

# Name of the product
product_name='VoipNow (R)'

# Version of installer
ver='5.5.0 M1'

# Version file
vfileold='/usr/local/voipnow/.version'
vfile='/etc/voipnow/.version'

# Configuration files
config_sqldbase=/etc/voipnow/sqldbase.conf
config_main=/etc/voipnow/main.conf

# Assumed VoipNow root directory
voipnowrootd=/usr/local/voipnow

# Customize shell
PS1='\[\033[02;32m\]\u@\h:\[\033[02;34m\]\w\$\[\033[00m\] '
RED='\033[0;31m'
GREEN='\033[0;42m'
NC='\033[0m'

# MySQL backup
ptc='/usr/bin/pt-online-schema-change'

# Download site
dsite='https://download2.4psa.com/voipnow/latest'

# These packages should be excluded from repositories
exclude_pack='elasticsearch5*,elasticsearch7*'

# Supported OS code
sys='rhel'

die()
{
    echo
    echo "ERROR: $*"
    echo
    echo "Check the error reason, fix and try again."
    echo "You are welcome to open a support ticket at https://help.4psa.com!"
    echo
    rm -f ${repolocal} local$$
    exit 1
}

welcome() {

    curdepth=`pwd | wc -c`

    if [ "${curdepth}" -lt 4 ];then
        die "Please do not execute this script from system /"
    fi
    
    echo
    echo    
    echo    "${product_name} ${ver} database upgrader."
    echo
    echo
    echo    "Please run this script off hours. For a large database execution may take several hours."
    case "$option" in
        es)
            echo "Upgrading Elasticseach only."
        ;;
        mysql)
            echo "Upgrading MySQL only."
        ;;
        *)    
            echo "Upgrading MySQL and Elasticsearch."
        ;;
    esac
    echo
    echo     "DO NOT STOP THE UPGRADE ONCE STARTED!"
    echo
    echo
    echo "Do you want to continue (Yes/No)? [Y] "
    
    read answer

    case "${answer}" in
        y*|Y*)
        ;;
        *)
            echo
            echo "You will be able to upgrade the database later."
            echo
            exit 1
        ;;
    esac
    echo
}

check_db()
{
    DO_MYSQL=1
    if [ -f ${config_main} ];then 
        # has been the table altered?
        mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWD} -e"SHOW COLUMNS FROM voipnow.extension_fax_center LIKE 'callid';" | grep -i "decimal" >/dev/null 2>&1
        if [ $? -eq 0 ];then
            DO_MYSQL=0
        fi
    else
        die "${product_name} is not installed, cannot upgrade MySQL!"
    fi
}

origin_find()
{
    # Determine installer course
    if [ -n "${VOIPNOW_REPO}" ];then
        origin=${VOIPNOW_REPO}/${sys}${release}/repo.dep
        dsite=${VOIPNOW_REPO}
        cm=1
    else
        origin=${dsite}/${sys}${release}/repo.dep
        cm=0
    fi
}

check_os()
{
    if [ -f /etc/redhat-release ];then     
        release=`cat /etc/redhat-release | cut -d'.' -f1 | awk '{print $NF}'`
    else
        echo
        echo "${product_name} runs on CentOS and Red Hat Enterprise Linux only!"
        exit 127   
    fi
    
    platform=`uname -i`
    if [ "${platform}" != "x86_64" ];then
        echo
        echo "${product_name} runs only on x86 64 bit platforms only!"
        exit 127
    fi
    
    if [ "${release}" = "6" ];then
        echo
        echo "******************************"
        echo
        echo "This is the LAST VERSION of ${product_name} that runs on CentOS / Red Hat Enterprise Linux versions 6!"
        echo "Please upgrade ASAP to CentOS 8 or Red Hat Enterprise Linux versions 8!"
        echo
        echo "******************************"
        echo
    fi
    
    if [ "${release}" == "7" ];then
        echo
        echo "--------------------------------------------------------------"
        echo
        echo "IMPORTANT - OS NOTICE:"
        echo
        echo "While `cat /etc/redhat-release` is still supported by ${product_name}, we strongly recommend the migration to CentOS 8 or Red Hat Enterprise Linux versions 8!"
        echo "Starting with 2021 Q3, support for `cat /etc/redhat-release` will be discontinued."
        echo
        echo "--------------------------------------------------------------"
        echo
        gpgkey="/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-7"
        crepo="os"
    fi

    if [ "${release}" == "8" ];then
        gpgkey="/etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial"
        crepo="BaseOS"
    else
        gpgkey="/etc/pki/rpm-gpg/RPM-GPG-KEY-CentOS-${release}"
        crepo="os"
    fi
    
    container=0
    if [ -f /proc/1/cgroup ];then
        upproc=`cat /proc/1/cgroup | cut -d: -f3 | sed 's/\///g' | sed '/^\s*$/d' | wc -l`
        if [ "${upproc}" -gt "0" ];then
            container=1
        fi
    fi
    
    if [ "${VNDEBUG}" ];then
        debugrpm='--rpmverbosity=debug'
    else
        debugrpm=''
    fi
}

check_deps()
{
    if [ "${release}" == "6" -o "${release}" == "7" ];then
        which yum >/dev/null 2>&1
        if [ $? -gt 0 ];then
            echo "yum binary can not be found."
            die "It's not in the system PATH or in a standard location."
        else
            pm="yum"
        fi
    fi
    
    if [ "${release}" == "8" ];then
        which dnf >/dev/null 2>&1
        if [ $? -gt 0 ];then
            echo "dnf binary can not be found."
            die "It's not in the system PATH or in a standard location."
        else
            pm="dnf"
        fi
    fi
    
}

get_pmconf()
{
    local repo=''
    curl -f --connect-timeout 20 -L ${origin} -o ${repolocal} >/dev/null 2>&1
    if [ ! -f ${repolocal} ];then
        die "Could not download from origin: ${origin}"
    fi
           
    # Replace the standard destination with another one
    dsite_host=`echo ${dsite} | awk -F/ '{url=$1"//"$3; print url}'`
    
    local alldeps=`grep "^http" ${repolocal} | sed -e "s#http.*://download2.4psa.com#${dsite_host}#g"`
    
    if [ -z "${alldeps}" ];then
        die "Repository file downloaded from ${origin} is invalid!"
    fi
    
    if [ -f ${pmconf} ];then
        mv -f ${pmconf} ${pmconf}.old
    fi
    
    cat <<EOT > ${pmconf}
[main]
cachedir=/var/cache/voipnow
keepcache=0
debuglevel=2
logfile=${update_log}
diskspacecheck=1
exactarch=1
obsoletes=1
metadata_expire=300
installonly_limit=3
reposdir=./
exclude=${exclude_pack}
plugins=1
ip_resolve=4

EOT
            
    for repo in ${alldeps};do
        curl -f --connect-timeout 20 -L ${repo} -o local$$ >/dev/null 2>&1
        if [ "$?" -eq "0" -a -f local$$ ];then
            local localrepo=`grep "^\[" local$$ | cut -d "[" -f 2 | cut -d "]" -f1`
            voipnowrepo="${voipnowrepo} ${localrepo}"
            
            disablevoipnow="${disablevoipnow} --disablerepo=${localrepo}"
            
            cat local$$ | sed -e "s#http.*://download2.4psa.com#${dsite_host}#g" >> ${pmconf}
            echo >> ${pmconf}
            rm -f local$$
        else
            die "Could not download from origin repo: ${repo}"
        fi
    done
    
    # Modify hubwall to skip module checks
    if [ "${release}" == "8" ];then
        sed -i '/\[hubwall-/ a module_hotfixes=True' ${pmconf}
    
    fi
    
    # Comment mirrors if needed
    if [ "${cm}" -eq "1" ];then
        sed -i -e "s/mirrorlist=/#mirrorlist=/g" ${pmconf}
        if [ "${SIGN_CHECK}" == "0" ];then
            sed -i -e "s/gpgcheck=1/gpgcheck=0/g" ${pmconf}        
        fi
    fi
    
    # Add OS repositories
    
    if [ "${release}" == "6" ];then

        cat <<EOT >> ${pmconf}

[base]
name=CentOS-\$releasever - Basemirrorlist=http://mirrorlist.centos.org/?release=\$releasever&arch=\$basearch&repo=${crepo}
baseurl=http://vault.centos.org/centos/\$releasever/os/\$basearch/
gpgcheck=1
gpgkey=file://${gpgkey}

[updates]
name=CentOS-\$releasever - Updates
baseurl=http://vault.centos.org/centos/\$releasever/updates/\$basearch/
gpgcheck=1
gpgkey=file://${gpgkey}
EOT
    
    else

        cat <<EOT >> ${pmconf}
        
[base]
name=CentOS-\$releasever - Base
mirrorlist=http://mirrorlist.centos.org/?release=\$releasever&arch=\$basearch&repo=${crepo}&infra=\$infra
#baseurl=http://mirror.centos.org/centos/\$releasever/os/\$basearch/
gpgcheck=1
gpgkey=file://${gpgkey}
EOT
    fi
    

    if [ "${release}" == "7" ];then
        cat <<EOT >> ${pmconf}

[updates]
name=CentOS-\$releasever - Updates
mirrorlist=http://mirrorlist.centos.org/?release=\$releasever&arch=\$basearch&repo=updates&infra=\$infra
gpgcheck=1
gpgkey=file://${gpgkey}
EOT
    fi

    if [ "${release}" == "8" ];then
        cat <<EOT >> ${pmconf}

[AppStream]
name=CentOS-\$releasever - AppStream
mirrorlist=http://mirrorlist.centos.org/?release=\$releasever&arch=\$basearch&repo=AppStream&infra=\$infra
gpgcheck=1
enabled=1
gpgkey=file://${gpgkey}

[PowerTools]
name=CentOS-\$releasever - PowerTools
mirrorlist=http://mirrorlist.centos.org/?release=\$releasever&arch=\$basearch&repo=PowerTools&infra=\$infra
gpgcheck=1
enabled=1
gpgkey=file://${gpgkey}
EOT
    fi
    cat <<EOT >> ${pmconf}    

[epel]
name=Extra Packages for Enterprise Linux \$releasever - \$basearch
#baseurl=http://download.fedoraproject.org/pub/epel/\$releasever/Everything/\$basearch
metalink=https://mirrors.fedoraproject.org/metalink?repo=epel-\$releasever&arch=\$basearch&infra=\$infra&content=\$contentdir
enabled=1
gpgcheck=1
gpgkey=https://download.fedoraproject.org/pub/epel/RPM-GPG-KEY-EPEL-${release}
EOT
    return 0
}

install_mysql()
{
    # start installation only when not installed
    if [ ! -f /etc/voipnow/.mysql ];then
        echo
        echo "==> Starting ${product_name} procedure."
        echo "This process will take a while ..."
        echo

        # performs installation
        ${pm} ${step} -c ${pmconf} install MariaDB-server MariaDB-client MariaDB-shared tzdata voipnow-nodeconfig
        
        which mysql > /dev/null 2>&1
        
        if [ "$?" -eq "0" ];then
            mkdir /etc/voipnow > /dev/null 2>&1
            touch /etc/voipnow/.mysql > /dev/null 2>&1
        else
            die "MySQL was not installed. Unknown error."
        fi
    fi
}

selinux_cleanup()
{
    # Remove old nodejs port definition
    semanage port -d -t node_port_t -p tcp 40001 >/dev/null 2>&1 || :
    semanage port -d -t node_port_t -p tcp 40002 >/dev/null 2>&1 || :
    semanage port -d -t node_port_t -p tcp 40003 >/dev/null 2>&1 || :

    semodule -l | grep -E "^nodejs|^kamailio|voipnow-asterisk|voipnow-httpsa|voipnow-phpfpm|voipnow-elasticsearch|voipnow-mysql" > /dev/null 2>&1
    if [ "$?" -eq "0" ]; then
        #Remove old selinux modules

        semanage port -d -t elasticsearch_port_t -p tcp 9200 >/dev/null 2>&1 || :
        semanage port -d -t elasticsearch_port_t -p tcp 9300 >/dev/null 2>&1 || :

        semanage port -d -t node_port_t -p tcp 17000-17999 >/dev/null 2>&1 || :
        semanage port -d -t voipnow_imm_port_t -p tcp 14000-14999 >/dev/null 2>&1 || :

        if [ "${release}" == "6" ]; then
            semodule -n -r jabberd rabbitmq voipnow-celery voipnow-epmd asterisk phpfpm httpsa nodejs elasticsearch kamailio hubring s3queuegc s3queueupldel voipnow-s3queuegc voipnow-s3queueupldel voipnow-selinux-collect voipnow-asterisk voipnow-collectd voipnow-common voipnow-elasticsearch voipnow-httpsa voipnow-hubring voipnow-kamailio voipnow-mysql voipnow-nodejs voipnow-phpfpm voipnow-s3queue voipnow-ejabberd > /dev/null 2>&1
        elif [ "${release}" == "7" ]; then
            semodule -n -X 100 -r asterisk -X 400 -r jabberd -X 400 -r rabbitmq -X 400 -r voipnow-celery -X 400 voipnow-epmd -X 400 -r phpfpm -X 400 -r httpsa -X 400 -r asterisk -X 400 -r nodejs -X 400 -r elasticsearch -X 400 -r kamailio -X 400 -r hubring -X 400 -r s3queuegc -X 400 -r s3queueupldel -X 400 -r voipnow-s3queuegc -X 400 -r voipnow-s3queueupldel -X 400 -r voipnow-selinux-collectd -X 400 -r voipnow-asterisk -X 400 -r voipnow-collectd -X 400 -r voipnow-common -X 400 -r voipnow-elasticsearch -X 400 -r voipnow-httpsa -X 400 -r voipnow-hubring -X 400 -r voipnow-kamailio -X 400 -r voipnow-mysql -X 400 -r voipnow-nodejs -X 400 -r voipnow-phpfpm -X 400 -r voipnow-s3queue -X 400 -r voipnow-ejabberd  > /dev/null 2>&1
        fi

        rpm -e voipnow-selinux --nodeps --noscripts > /dev/null 2>&1
        /sbin/load_policy
    fi
}

upgrade_mysql()
{
    echo
    if [ "${ALT_DB_USER}" -a "${ALT_DB_PASSWD}" -a "${ALT_DB_PORT}" -a "${ALT_DB_HOST}" ];then
        DB_USER=${ALT_DB_USER}
        DB_PASSWD=${ALT_DB_PASSWD}
        DB_PORT=${ALT_DB_PORT}
        DB_HOST=${ALT_DB_HOST}
        DB_NAME=${ALT_DB_NAME}
    else
        if [ -f /etc/voipnow/.sqldb ]; then
            DB_USER=`grep "^main" /etc/voipnow/.sqldb | cut -d: -f2`
            DB_PASSWD=`grep "^main" /etc/voipnow/.sqldb | cut -d: -f3`
            DB_HOST=`grep "^DB_MASTER\>" /etc/voipnow/sqldbase.conf | awk '{print $2}' | grep "^main" | cut -d: -f2`
            DB_PORT=`grep "^DB_MASTER\>" /etc/voipnow/sqldbase.conf | awk '{print $2}' | grep "^main" | cut -d: -f3`
            DB_NAME=`grep "^DB_CREDENTIALS\>" ${config_main} | awk '{print $2}' | grep "^main" | cut -d: -f4`
        fi        
    fi
        
    # can we access mysql?
    if [ "${DB_USER}" -a "${DB_PASSWD}" -a "${DB_PORT}" ];then
        mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWD} -e"SHOW VARIABLES LIKE '%version%';" >/dev/null 2>&1
        if [ $? -gt 0 ];then
            die "Cannot connect to MySQL server as root, MySQL database upgrade will not be performed!"
        fi
    else
        die "Cannot get the credentials in order to access MySQL server."
    fi
}

do_mysql()
{
    if [ ! -f ${ptc} ];then
        echo
        echo "MySQL tools could not be installed."
        echo "Please open a support ticket in 4PSA Support Zone."
        echo
        exit 99
    fi
    
    if [ ${DO_MYSQL} -eq 0 ];then
        echo "It seems like your MySQL database has been already upgraded to ${product_name} ${ver} schema."
        return 0
    fi

    echo
    echo "==> Staring MySQL upgrade procedure, please DO NOT STOP THIS PROCESS!"
    echo

    ${ptc} h=${DB_HOST},P=${DB_PORT},D=${DB_NAME},t=call_history,u=${DB_USER},p=${DB_PASSWD} --alter "MODIFY callid DECIMAL (19,9) DEFAULT NULL, MODIFY parent_callid DECIMAL (19,9) DEFAULT NULL, ADD KEY callid (callid), ADD KEY did (did), ADD KEY cl_client_id (client_client_id), LOCK=SHARED;" --execute --statistics --no-version-check
    diem $? call_history
    ${ptc} h=${DB_HOST},P=${DB_PORT},D=${DB_NAME},t=extension_recording,u=${DB_USER},p=${DB_PASSWD} --alter "MODIFY callid DECIMAL (19,9) DEFAULT NULL, ADD resource_type varchar(64) NOT NULL DEFAULT '', ADD resource_id varchar(255) NOT NULL DEFAULT '', LOCK=SHARED;" --execute --statistics --no-version-check
    diem $? extension_recording
    ${ptc} h=${DB_HOST},P=${DB_PORT},D=${DB_NAME},t=extension_voicemail,u=${DB_USER},p=${DB_PASSWD} --alter "MODIFY callid DECIMAL (19,9) DEFAULT NULL, LOCK=SHARED;" --execute --statistics --no-version-check
    diem $? extension_voicemail
    ${ptc} h=${DB_HOST},P=${DB_PORT},D=${DB_NAME},t=extension_fax_center,u=${DB_USER},p=${DB_PASSWD} --alter "MODIFY callid DECIMAL (19,9) DEFAULT NULL, LOCK=SHARED;"  --execute --statistics --no-version-check
    diem $? extension_fax_center

    echo
    echo "OK!"
}

do_es1()
{
    [ -f /etc/voipnownode/nodeid ] && nodeid=`cat /etc/voipnownode/nodeid`
        
    if [ -n ${nodeid} ];then
    
        is_ic=`mysql -h${DB_HOST} -P${DB_PORT} -u${DB_USER} -p${DB_PASSWD} ${DB_NAME} -N -e"SELECT count(nodeid) FROM node_role WHERE role='ic' AND nodeid='${nodeid}' AND status=1"`
        
        if [ "${is_ic}" -eq "1" ];then
            # is elasticsearch installed?
            rpm -q elasticsearch > /dev/null
            if [ $? -eq 0 -a ! -f /etc/voipnow/.es1_uc ];then
                echo
                selinux_cleanup
                ${pm} -y -c ${pmconf} install elasticsearch-upgrade
                if [ -f ${voipnowrootd}/etc/es/upgradees1/migrate-es2.js ];then
                    echo
                    echo "==> Executing upgrade preparations for ES 2 (this might take a while, DO NOT STOP)..."
                    NODE_PATH=/usr/lib/node_modules node ${voipnowrootd}/etc/es/upgradees1/migrate-es2.js ${voipnowrootd}/etc/es/upgradees1/templates > es1_upgrade_`date | sed 's/ /_/g'`.log
                    if [ $? -eq 0 ];then
                        echo `date` > /etc/voipnow/.es1_uc
                        rpm -e elasticsearch --nodeps >/dev/null 2>&1
                        echo
                        echo "OK!"
                    else
                        die "Critical, Elasticsearch upgrade failed! Please contact support."
                    fi
                fi
            fi
        fi
    fi
}

do_es2()
{
    rpm -q elasticsearch > /dev/null
    if [ $? -gt 0 ];then    
        rpm -q elasticsearch-schema > /dev/null
        if [ $? -gt 0 ];then
            echo
            echo "==> Executing ES 2 reindex (this might take a while, DO NOT STOP)..."
            ${pm} -y -c ${pmconf} install elasticsearch-schema
        fi
    else
        die "There is a problem with your Elasticsearch upgrade. Please contact support."
    fi
}

pm_update()
{
    if [ ! -f ${ptc} ];then 
        echo
        echo "==> Upgrading MySQL tools..."
        rpm -q percona-toolkit > /dev/null
        if [ $? -gt 0 ];then
            ${pm} -y -c ${pmconf} install percona-toolkit
        else
            ${pm} -y -c ${yumconf} update percona-toolkit
        fi
    fi
}

diem()
{
    err=$1
    table=$2
    
    if [ ${err} -gt 0 ];then
        echo
        echo "An error has occured during MySQL table ${table} upgrade."
        echo "Please open a support ticket in 4PSA Support Zone."
        echo
        exit 99
    fi
}

# main
repolocal=repo.dep$$
pmconf=/etc/voipnow-yum.conf

option=$1

welcome
check_os
check_deps
origin_find
get_pmconf
pm_update
upgrade_mysql
check_db

case "$option" in
    es)
        do_es1
        do_es2
    ;;
    mysql)
        do_mysql
    ;;
    *)    
        do_mysql
        do_es1
        do_es2
    ;;
esac

echo
echo
echo "Upgrade completed. Bye!"
echo

exit 0
