#!/bin/bash

readonly progname="${0##*/}"

XDS_RSYNC_KEY_PATH="/root/.ssh/"
XDS_RSYNC_KEY_NAME="rsync_xds"

usage() {
    echo "${progname} [-i|-s|-n]
    -i | --init : Generate a key pair for rsync to the XDS servers and print setup info
    -s | --sync : Start a silent rsync to all MDS (logged to /var/syslog)
    -n | --dry  : Start a dry rsync run (logged to /var/log/syslog)
    _____________________________________________________________________________________

    Any file prefixed by xds_override in the sync dir will be excluded from the process.
    "
}

exit_abnormally() {
    usage
    exit 1
}

init() {
    # shellcheck disable=SC2155
    local xivo_ip=$(hostname -I | cut -d\  -f 1)

    apt install rsync -y

    if [ -e "${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}" ]; then
        echo "INFO: there is already an rsync_xds key pair."
    else
        ssh-keygen -f "${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}" -t rsa -N "" -C "XiVO Main - XDS Sync"
    fi

    cp "${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}.pub" /usr/share/xivo-certs/rsync_xds.pub

    if [ -e /etc/cron.d/xivo-xds-sync ]; then
        echo "INFO: there is already a xivo-xds-sync cron job."
    else
        echo "creating cron job /etc/cron.d/xivo-xds-sync."
		cat > /etc/cron.d/xivo-xds-sync <<-EOF
			#
			# cron jobs for xivo-xds-sync
			#

			*/15 * * * * root /usr/sbin/xivo-xds-sync -s > /dev/null
		EOF
    fi

    echo ""
    echo -e "\e[1;32mXDS File Synchronization Initialization : done\e[0m"
    echo "To finish the installation you MUST install the XiVO Main pub key on all the MDS"
    echo "To do so: execute the following commands on each MDS:"
    echo ""
    echo "mkdir -p /root/.ssh/ && wget https://${xivo_ip}/ssh-key --no-check-certificate -O ${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}.pub && cat ${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}.pub >> /root/.ssh/authorized_keys && apt install rsync -y"
    echo ""
}

get_mds_list() {
    local mds_ip_list
    if ! mds_ip_list=$(psql -U asterisk -d asterisk --quiet -tAc "select voip_ip from mediaserver where name <> 'default';"); then
        echo "ERROR: Could not retrieve MDS IP. Database error. Exiting"
        exit 1
    else
        echo "${mds_ip_list}"
    fi
}

rsync_cmd() {
    local rsync_custom_opts="${1}"; shift
    local rsync_src="${1}"; shift
    local rsync_dst="${1}"; shift

    # shellcheck disable=SC2086
    rsync \
        -e "ssh -o StrictHostKeyChecking=no -i ${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}" \
        -a -v --timeout=30 --exclude 'xds_override*' \
        ${rsync_custom_opts} \
        "${rsync_src}" "${rsync_dst}"
}

sync() {
    # mode: can be one of sync or dry_run
    local mode="${1}"; shift
    local mds_ip_list="${1}"; shift
    local rsync_dryrun_opt=""


    if [ "${mode}" = "dry_run" ]; then
        rsync_dryrun_opt="-n"
        echo "Sync launched in dry run mode. Look in /var/log/syslog for results."
    else
        rsync_dryrun_opt=""
    fi

    echo "XDS Sync: Start" | logger -t "${progname}"
    for mds_ip in ${mds_ip_list} ;
    do
        echo "------"
        echo "Start: Sync to MDS (${mds_ip})"
        echo "- syncing dir /etc/asterisk/extensions_extra.d/"
        rsync_cmd "${rsync_dryrun_opt}" "/etc/asterisk/extensions_extra.d/" "root@${mds_ip}:/etc/asterisk/extensions_extra.d/" 2>&1

        echo ""
        echo "- syncing dir /var/lib/xivo/moh/"
        rsync_cmd "--delete ${rsync_dryrun_opt}" "/var/lib/xivo/moh/" "root@${mds_ip}:/var/lib/xivo/moh/" 2>&1

        echo ""
        echo "- syncing dir /var/lib/xivo/sounds/recordings/ (both ways)"
        echo "  - Main >>>>> MDS"
        rsync_cmd "-u ${rsync_dryrun_opt}" "/var/lib/xivo/sounds/recordings/" "root@${mds_ip}:/var/lib/xivo/sounds/recordings/" 2>&1
        echo "  - MDS  >>>>> Main"
        rsync_cmd "-u ${rsync_dryrun_opt}" "root@${mds_ip}:/var/lib/xivo/sounds/recordings/" "/var/lib/xivo/sounds/recordings/" 2>&1

        echo ""
        echo "- syncing dir /var/lib/xivo/sounds/"
        rsync_cmd "--delete ${rsync_dryrun_opt}" "/var/lib/xivo/sounds/" "root@${mds_ip}:/var/lib/xivo/sounds/" 2>&1

        if [ "${mode}" != "dry_run" ]; then
            echo ""
            echo "- reloading dialplan on mds"
            ssh -i ${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME} -o ConnectTimeout=30 "root@${mds_ip}" "asterisk -rx 'dialplan reload'" 2>&1
            echo ""
            echo "- reloading moh on mds"
            ssh -i ${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME} -o ConnectTimeout=30 "root@${mds_ip}" "asterisk -rx 'moh reload'" 2>&1
        fi
        echo "Done: Sync to MDS (${mds_ip})"
    done | logger -t "${progname}"
    echo "XDS Sync: Done" | logger -t "${progname}"
}

check_init() {
    if [ ! -e "${XDS_RSYNC_KEY_PATH}${XDS_RSYNC_KEY_NAME}" ]; then
        echo "ERROR:  rsync_xds key pair is not present. Can't continue."
        echo "ERROR:  Did you run XDS File Sync initialization ?"
        echo "ERROR:  If not, please run:"
        echo "ERROR:     ${progname} -i"
        exit 1
    fi
}

# This function is called when script exit
# and it logs a message in syslog if script exited with non-zero
display_error_in_log() {
    local returnvalue=$?
    if [ $returnvalue -ne "0" ]; then
        echo "ERROR: XDS Sync failed to run properly. Try it on command line to see error." | logger -t "${progname}"
    fi
}

main() {
    # Function will execute each time script exits
    trap display_error_in_log EXIT

    if [ -e /var/lib/xivo/mds_enabled ]; then
        echo "ERROR: This script must not be run on MDS. It has to be run on XiVO Main."
        echo "Refer to the documentation: Administrator's Guide > XiVO > XDS > File Sync"
        exit 1
    fi
    if [ -z "${1}" ] || [ -n "${2}" ]; then
        echo "ERROR: This script can be run only with exactly one argument."
        exit_abnormally
    fi

    local mode=""
    case "${1}" in
        -i | --init )
            mode="init"
            ;;
        -s | --sync )
            mode="sync"
            ;;
        -n | --dry )
            mode="dry_run"
            ;;
        -h | --help )
            usage
            ;;
        * )
            echo "ERROR: unknown argument ${1}"
            exit_abnormally
            ;;
    esac

    if [ "${mode}" = "init" ]; then
        init
    elif [ "${mode}" = "sync" ] || [ "${mode}" = "dry_run" ]; then
        if ! check_init; then
            exit 1
        fi
        local mds_ip_list
        if ! mds_ip_list=$(get_mds_list); then
            echo "ERROR: Couldn't retrieve correctly MDS IP list"
            echo "${mds_ip_list}"
            exit 1
        else
            if [ -z "${mds_ip_list}" ]; then
                echo "ERROR: Retrieved MDS IP list is empty. Can't continue. Exiting."
                exit 1
            fi
            sync "${mode}" "${mds_ip_list}"
        fi
    fi

    exit 0
}

main "${@}"
