#!/usr/bin/env bash
# vim:foldmarker={,}
# vim:foldmethod=marker
# vim: ts=4 sw=4 et

export LC_ALL=C
# set -o errexit
# set -o nounset
# set -o pipefail
if [[ -n "${TRACE-}" ]]; then
    set -o xtrace
fi

#
# ClusterControl is a management and monitoring application for your database infrastructure.
# The installation script installs the frontend, backend and a LAMP stack.
#

ask() {
    if [[ ! -z $PROMPT_USER ]]; then
        read -p "$1" x
        [[ -z "$x" ]] || [[ "$x" == ["$2${2^^}"] ]] && return 0

        return 1
    else
        # always return true when prompt user is off
        return 0
    fi
}

ask_p() {
    [[ ! -z $S9S_CMON_PASSWORD ]] && return 0
    read -p "$1" x
    [[ -z "$x" ]] || [[ "$x" == ["$2${2^^}"] ]] && return 0

    return 1
}

confirm() {
    read -p "$1" x
    [[ -z "$x" ]] || [[ "$x" == ["$2${2^^}"] ]] && return 0

    return 1
}

ask_generic_distro() {
    PS3="Please select a generic distribution or exit the installation: "
    options=("redhat" "debian" "exit")
    select opt in "${options[@]}"
    do
        case $opt in
            "redhat")
                dist="redhat"
                break
                ;;
            "debian")
                dist="debian"
                break
                ;;
            "exit")
                exit 1
                ;;
            *) echo invalid option;;
        esac
    done
}

do_lsb() {
    os_codename=$(lsb_release -sc)
    os_release=$(lsb_release -rs)
    if [[ -f /etc/centos-release || -f /etc/redhat-release ]]; then
        $(echo $os_release | grep -q "7.")
        [[ $? -eq 0 ]] && rhel_version=7
        $(echo $os_release | grep -q "8.*")
        [[ $? -eq 0 ]] && rhel_version=8
        $(echo $os_release | grep -q "9.*")
        [[ $? -eq 0 ]] && rhel_version=9

        [[ -f /etc/centos-release ]] && CENTOS=1
        [[ -f /etc/oracle-release ]] && ORACLE=1 && yum install -y oraclelinux-release-el${rhel_version}
    fi

    lsb=$(lsb_release -d)
    [[ $lsb =~ $regex_lsb ]] && dist=${BASH_REMATCH[1]} ; return 0
    return 1
}

do_release_file() {
    etc_files=$(ls /etc/*[-_]{release,version} 2>/dev/null)
    for file in $etc_files; do
        if [[ $file =~ $regex_etc ]]; then
            dist=${BASH_REMATCH[1]}
            # tolower. bash subs only in bash 4.x
            #dist=${dist,,}
            dist=$(echo $dist | tr '[:upper:]' '[:lower:]')
            if [[ $dist == "redhat" || $dist == "red" || $dist == "fedora" ]]; then
                $(grep -q " 7." $file)
                [[ $? -eq 0 ]] && rhel_version=7 && break
                $(grep -q " 8.*" $file)
                [[ $? -eq 0 ]] && rhel_version=8 && break
                $(grep -q " 9.*" $file)
                [[ $? -eq 0 ]] && rhel_version=9 && break
                break
            else
                # AlmaLinux/RockyLinux.. etc other RedHat compatible ones
                $(grep -q "platform:el7" $file)
                [[ $? -eq 0 ]] && dist="redhat" && rhel_version=7 && break
                $(grep -q "platform:el8" $file)
                [[ $? -eq 0 ]] && dist="redhat" && rhel_version=8 && break
                $(grep -q "platform:el9*" $file)
                [[ $? -eq 0 ]] && dist="redhat" && rhel_version=9 && break
            fi
        fi
    done
    [[ -f /etc/centos-release ]] && CENTOS=1
    [[ -f /etc/oracle-release ]] && ORACLE=1 && yum install -y oraclelinux-release-el${rhel_version}
}

add_s9s_apt () {
    repo="deb [arch=amd64] ${repo_http_protocol}://repo.severalnines.com/deb ubuntu main"
    repo_source_file=/etc/apt/sources.list.d/s9s-repo.list
    if [[ ! -z ${USE_REPO} ]]; then
        repo="deb [arch=amd64] ${repo_http_protocol}://repo.severalnines.com/${USE_REPO}/deb ubuntu main"
        repo_source_file="/etc/apt/sources.list.d/s9s-${USE_REPO}.list"
    fi

    if [[ ! -e $repo_source_file ]]; then
        if [[ ! -z ${USE_REPO} ]]; then
            wget ${repo_http_protocol}://repo.severalnines.com/${USE_REPO}/severalnines-repos.asc -O- | apt-key add - && echo "$repo" | tee -a $repo_source_file
        else
            wget ${repo_http_protocol}://repo.severalnines.com/severalnines-repos.asc -O- | apt-key add - && echo "$repo" | tee -a $repo_source_file
        fi

        log_msg "Added ${repo_source_file}"
        log_msg "Updating repo ..."
        waitForLocks
        apt-get update
    else
        log_msg "Repo file $repo_source_file already exists"
        waitForLocks
        apt-get update
    fi
}

start_cmon_services() {
    if [[ $systemd == 1 ]]; then
        pidof -s cmon-events &>/dev/null || systemctl start cmon-events
        systemctl enable cmon-events
        pidof -s cmon-ssh &>/dev/null || systemctl start cmon-ssh
        systemctl enable cmon-ssh
        pidof -s cmon-cloud &>/dev/null || systemctl start cmon-cloud
        systemctl enable cmon-cloud
    else
        pidof -s cmon-events &>/dev/null || service cmon-events start
        pidof -s cmon-ssh &>/dev/null || service cmon-ssh start
        pidof -s cmon-cloud &>/dev/null || service cmon-cloud start

        if [[ "$dist" == "debian" ]]; then
            update-rc.d cmon-events defaults
            update-rc.d cmon-ssh defaults
            update-rc.d cmon-cloud defaults
        else
            chkconfig --levels 235 cmon-ssh on
            chkconfig --levels 235 cmon-events on
            chkconfig --levels 235 cmon-cloud on
        fi
    fi
}

add_s9s_commandline_apt() {
    # Available distros: wheezy, jessie, precise, trusty, xenial, yakkety, zesty
    repo_source_file=/etc/apt/sources.list.d/s9s-tools.list
    if [[ ! -e $repo_source_file ]]; then
        wget -qO - ${repo_http_protocol}://repo.severalnines.com/s9s-tools/${os_codename}/Release.key | apt-key add -
        echo "deb ${repo_http_protocol}://repo.severalnines.com/s9s-tools/${os_codename}/ ./" | tee /etc/apt/sources.list.d/s9s-tools.list
    else
        log_msg "Repo file $repo_source_file already exists"
    fi
}

add_s9s_yum () {
    repo_source_file=/etc/yum.repos.d/s9s-repo.repo
    [[ ! -z ${USE_REPO} ]] && repo_source_file="/etc/yum.repos.d/s9s-repo-${USE_REPO}.repo"
    if [[ ! -e $repo_source_file ]]; then
        if [[ ! -z ${USE_REPO} ]]; then
            cat > $repo_source_file << EOF
[s9s-repo-${USE_REPO}]
name=Severalnines ${USE_REPO} Repository
baseurl = ${repo_http_protocol}://repo.severalnines.com/${USE_REPO}/rpm/os/x86_64
enabled = 1
gpgkey = ${repo_http_protocol}://repo.severalnines.com/${USE_REPO}/severalnines-repos.asc
gpgcheck = 1
EOF
        else
            cat > $repo_source_file << EOF
[s9s-repo]
name=Severalnines Repository
baseurl = ${repo_http_protocol}://repo.severalnines.com/rpm/os/x86_64
enabled = 1
gpgkey = ${repo_http_protocol}://repo.severalnines.com/severalnines-repos.asc
gpgcheck = 1
EOF
        fi
        log_msg "Added ${repo_source_file}"
    else
        log_msg "Repo file $repo_source_file already exists"
    fi
}

add_s9s_commandline_yum() {
    repo_source_file=/etc/yum.repos.d/s9s-tools.repo
    if [[ ! -e $repo_source_file ]]; then
        if [[ -z $CENTOS ]]; then
            REPO="RHEL_7"
            [[ $rhel_version == "8" ]] && REPO="RHEL_8"
            [[ $rhel_version == "9" ]] && REPO="RHEL_9"
        else
            REPO="CentOS_7"
            [[ $rhel_version == "8" ]] && REPO="CentOS_8"
            [[ $rhel_version == "9" ]] && REPO="CentOS_9"
        fi
        cat > $repo_source_file << EOF
[s9s-tools]
name=s9s-tools (${REPO})
type=rpm-md
baseurl=${repo_http_protocol}://repo.severalnines.com/s9s-tools/${REPO}
gpgcheck=1
gpgkey=${repo_http_protocol}://repo.severalnines.com/s9s-tools/${REPO}/repodata/repomd.xml.key
enabled=1
EOF
        log_msg "Added ${repo_source_file}"
    else
        log_msg "Repo file $repo_source_file already exists"
    fi
}

find_mysql() {
    mysql_bin="/usr/bin/mysql"
    if ! command -v mysql &>/dev/null; then
        log_msg "Cannot find a mysql client in your PATH!"
        log_msg "Provide the full path to your mysql client, for example /opt/mysql/bin/mysql"
        read -p "=> Absolute path to the MySQL client: " x
        [[ ! -z $x ]] && mysql_bin="$x"
        [[ ! -f $mysql_bin ]] && { log_msg "Cannot find ${mysql_bin}. ..."; exit 1; }
    fi
}

install_frontend() {
    clustercontrol_build=${CLUSTERCONTROL_BUILD:-"clustercontrol2"}
    if [[ ${cc_version} == "2" ]]; then
        clustercontrol_build=${CLUSTERCONTROL_BUILD:-"clustercontrol2"}
    elif [[ ${cc_version} == "3" ]]; then
        clustercontrol_build=${CLUSTERCONTROL_BUILD:-"clustercontrol-mcc clustercontrol-notifications clustercontrol-ssh clustercontrol-cloud"}
    fi
    log_msg "Installing ClusterControl frontend packages ..."
    if [[ $dist == "debian" ]]; then
        waitForLocks
        if [[ -z ${OFFLINE+x} ]]; then
            add_s9s_commandline_apt
            add_s9s_apt
        fi
        waitForLocks
        LC_ALL=en_US.utf8 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true  apt-get -yq install ${clustercontrol_build} || { log_msg "Failed to install clustercontrol packages. (apt-get -yq install ${clustercontrol_build})"; exit 1; }
    elif [[ $dist == "redhat" ]]; then
        if [[ -z ${OFFLINE+x} ]]; then
            add_s9s_commandline_yum
            add_s9s_yum
        fi
        yum -yq install ${clustercontrol_build} || { log_msg "Failed to install clustercontrol packages. (yum -yq install ${clustercontrol_build})"; exit 1; }
    fi

    if [[ ${cc_version} == "2" ]]; then
        # change registration form
        [[ -f /var/www/html/clustercontrol2/config.js ]] && sed -i "s|^[ \t]*USER_REGISTRATION:.*|  USER_REGISTRATION: 1,|g" /var/www/html/clustercontrol2/config.js
        # check edition
        local cc_edition="${CC_EDITION:-##__CC_EDITION__##}"
        if [[ "${cc_edition}" == "1" ]]; then
            [[ -f /var/www/html/clustercontrol2/config.js ]] && sed -i "/^[ \t]*USER_REGISTRATION:.*/a\  COMMUNITY_EDITION: 1," /var/www/html/clustercontrol2/config.js
        fi
    fi
}

create_my_cnf() {

    cat > $1 << EOF
[mysqld]
user = mysql
#basedir = $mysql_basedir
datadir = $mysql_datadir
pid_file = $mysql_datadir/mysqld.pid
socket = $mysql_socket
port = ${db_port}
#log_error = error.log
max_allowed_packet = 128M
#event_scheduler = 1
innodb_buffer_pool_size = ${INNODB_BUFFER_POOL_SIZE}M
innodb_flush_log_at_trx_commit = 2
innodb_file_per_table = 1
#innodb_data_file_path = ibdata1:100M:autoextend
innodb_log_file_size = 512M
innodb_log_files_in_group = 2
#innodb_buffer_pool_instances = 4
innodb_thread_concurrency = 0
innodb_flush_method = O_DIRECT
sysdate_is_now = 1
max_connections = 512
thread_cache_size = 128
#table_open_cache=512
lower_case_table_names = 0
#skip_name_resolve
skip-log-bin
EOF

    case "${os_codename}" in
        'disco' |'bionic'|'xenial'|'jammy'|'noble'|'stretch'|'buster'|'bullseye')
            cat >> $1 << EOF
plugin-load-add = auth_socket.so
EOF
        ;;
    esac

    cat >> $1 << EOF
[mysql]
socket=$mysql_socket

[client]
socket=$mysql_socket

[mysqld_safe]
pid-file=$mysql_datadir/mysqld.pid
#log-error=error.log
basedir=$mysql_basedir
datadir=$mysql_datadir
EOF

}

install_web_server() {
    case "${dist}" in
        'debian')
            www_user=www-data
            install_packages="apt-get -y install apache2"
            enable_mods="ssl rewrite headers proxy proxy_http proxy_wstunnel"
            cert_file="/etc/ssl/certs/s9server.crt"
            key_file="/etc/ssl/private/s9server.key"
            restart_apache="service apache2 restart"
            update_repo="apt-get update"

            if [[ -z ${OFFLINE+x} ]]; then
                if ask "=> Do $update_repo? (Y/n): " "y"; then
                    $update_repo
                fi
            fi

            if [[ -n $install_packages ]]; then
                waitForLocks
                LC_ALL=en_US.utf8 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true $install_packages
                [[ $? -ne 0 ]] && log_msg "Installing packages ${install_packages}, failed" && exit 1
            fi

            for m in $enable_mods; do
                log_msg "Enabling apache module ${m} ..."
                a2enmod $m
            done

            # enable sameorigin header
            if [[ -f /etc/apache2/conf-available/security.conf ]]; then
                # enable for header
                sed -ibak "s|^#Header set X-Frame-Options: \"sameorigin\"|Header set X-Frame-Options: \"sameorigin\"|g" /etc/apache2/conf-available/security.conf
                ln -sfn /etc/apache2/conf-available/security.conf /etc/apache2/conf-enabled/security.conf
            fi

            [[ -e /etc/apache2/sites-enabled/000-default.conf ]] && rm -f /etc/apache2/sites-enabled/000-default.conf

            # restart the web server after the controller has been installed
            ;;
        'redhat')
            apache_conf=/etc/httpd/conf/httpd.conf
            apache_conf_ssl=/etc/httpd/conf.d/ssl.conf
            www_user=apache
            install_packages="yum -y install httpd mod_ssl"
            enable_mods=""
            cert_file="/etc/pki/tls/certs/s9server.crt"
            key_file="/etc/pki/tls/private/s9server.key"
            restart_apache="service httpd restart"
            [[ ! -z $ORACLE ]] && restart_apache="systemctl restart httpd"
            update_repo="yum update"
            chkconfig_apache="chkconfig --levels 235 httpd on"

            if [[ -z ${OFFLINE+x} ]]; then
                if ! ask "=> Do $update_repo? (y/N): " "n"; then
                    $update_repo
                fi
            fi

            if [[ -n $install_packages ]]; then
                $install_packages &>/dev/null
                #[[ $? -ne 0 ]] && log_msg "Installing packages ${install_packages}, failed" && exit 1
            fi

            $chkconfig_apache

            apache_version=$(apachectl -v | grep -i "server version" | cut -d' ' -f3)
            [[ "${apache_version%.*}" == "Apache/2.4"  ]] && use_apache24=1

            if [[ ! -z $use_apache24 ]]; then
                # enable sameorigin header
                if [[ ! -f /etc/httpd/conf.d/security.conf ]]; then
                    # enable for header
                    cat > /etc/httpd/conf.d/security.conf << EOF
Header set X-Frame-Options: "sameorigin"
EOF
                fi
                # restart the web server after the controller has been installed
            fi
            ;;
    esac
    # generate new cert
    if command -v openssl &>/dev/null; then
        mkdir -p /tmp/ssl && cd /tmp/ssl
        create_cert
        # copy the files from the clustercontrol package
        cp -f /tmp/ssl/server.crt ${cert_file} &>/dev/null
        cp -f /tmp/ssl/server.key ${key_file} &>/dev/null
        rm -rf /tmp/ssl &>/dev/null
    fi
}

configure_ccv2_web() {
    # change default port 9443 to 443
    # ask to set the servername
    servername="${S9S_WEB_SERVER_HOST:-$host}"
    if [[ -z ${S9S_WEB_SERVER_HOST} ]]; then
        if ! ask_p "=> The Apache web 'ServerName' will be set to ${servername}. Do you want to change it? (y/N): " "n"; then
            read -p "=> Enter the 'ServerName': " x
            [[ ! -z $x ]] && servername="$x"
        fi
    fi
    log_msg "The Apache 'ServerName' will be set to ${servername} ..."

    case "${dist}" in
        'debian')
            sed -i "s|^[ \t]*ServerName.*|        ServerName ${servername}|g" /etc/apache2/sites-available/cc-frontend.conf
            if [[ ${cc_version} == "2" ]]; then
                sed -i "s|https://cc2.severalnines.local:9443.*|https://${servername}\/|g" /etc/apache2/sites-available/cc-frontend.conf
                sed -i "s|Listen 9443|#Listen 443|g" /etc/apache2/sites-available/cc-frontend.conf
                sed -i "s|9443|443|g" /etc/apache2/sites-available/cc-frontend.conf
            fi
            ;;
        'redhat')
            if [[ ! -e /etc/httpd/conf.d/cc-frontend.conf ]]; then
                [[ -e /usr/share/cmon/apache/cc-frontend.conf ]] && cp /usr/share/cmon/apache/cc-frontend.conf /etc/httpd/conf.d/
            fi
            sed -i "s|^[ \t]*ServerName.*|        ServerName ${servername}|g" /etc/httpd/conf.d/cc-frontend.conf
            if [[ ${cc_version} == "2" ]]; then
                sed -i "s|https://cc2.severalnines.local:9443.*|https://${servername}\/|g" /etc/httpd/conf.d/cc-frontend.conf
                sed -i "s|Listen 9443|#Listen 443|g" /etc/httpd/conf.d/cc-frontend.conf
                sed -i "s|9443|443|g" /etc/httpd/conf.d/cc-frontend.conf
            fi
            ;;
    esac
}

configure_mcc() {
    local web_port=${1:-443}
    local web_root="${2:-/var/www/html/clustercontrol-mcc}"

    log_msg "Configuring ccmgr (cmon-proxy) ..."
    ccmgradm init --local-cmon -p ${web_port} -f ${web_root}
    systemctl restart cmon-proxy || exit 1

    # log_msg "Please enter your first name: "
    # read first_name
    # log_msg "Please enter your last name: "
    # read last_name
    # log_msg "Please enter your email address: "
    # read admin_user_email

    # # create admin user
    # log_msg "Please enter an admin username: "
    # read admin_user
    # until set_admin_password; do
    #     log_msg ""
    #     log_msg "Password mismatch! Try again."
    #     sleep 1
    # done
    # [ -z ${admin_user_password+x} ] || S9S_ADMIN_USER_PASSWORD="${admin_user_password}"

    # s9s user --create --first-name=${first_name} --last-name=${last_name} --email-address="${admin_user_email}" \
    #     --new-password=${admin_user_password} --group=admins \
    #     --generate-key ${admin_user} || exit 1
}

install_database_server() {
    case "${dist}" in
        'debian')
            install_packages="apt install -y mysql-server mysql-client"
            [[ -n $use_existing_mysql ]] && install_packages=""
            stop_mysql="service mysql stop"
            start_mysql="service mysql start"
            update_repo="apt-get update"
            mysql_basedir=/usr
            mysql_datadir=/var/lib/mysql
            my_cnf=/etc/mysql/my.cnf
            mysql_socket="/var/run/mysqld/mysqld.sock"

            case "${os_codename}" in
                'jammy'|'noble')
                    install_packages="apt-get -y install mysql-server mysql-client wget"
                    [[ -n $use_existing_mysql ]] && install_packages="apt-get -y install wget"
                    ;;
                'buster')
                    install_packages="`echo $install_packages | sed 's/mysql-/default-mysql-/g'`"
                    ;;
                'bullseye'|'bookworm')
                    install_packages="`echo $install_packages | sed 's/mysql-/mariadb-/g'`"
                    ;;
            esac

            if [[ -z ${OFFLINE+x} ]]; then
                if ask "=> Do $update_repo? (Y/n): " "y"; then
                    $update_repo
                fi
            fi

            if [[ -n $install_packages ]]; then
                waitForLocks
                LC_ALL=en_US.utf8 DEBIAN_FRONTEND=noninteractive DEBCONF_NONINTERACTIVE_SEEN=true $install_packages
                [[ $? -ne 0 ]] && log_msg "Installing packages ${install_packages}, failed" && exit 1
            fi
            if [[ -z $use_existing_mysql ]]; then
                log_msg "Stoppping MySQL Server before updating configuration ..."
                #killall -15 mysqld mysqld_safe &>/dev/null
                $stop_mysql
                [[ $? -ne 0 ]] && [[ $stop_mysql != "" ]] && log_msg "Failed to stop the MySQL Server. ..." && exit 1

                create_my_cnf /tmp/my.cnf
                if [[ "${os_codename}" == "bookworm"  || "${os_codename}" == "bullseye" ]]; then
                    cp -f /tmp/my.cnf /etc/mysql/mariadb.conf.d/55-s9s-server.cnf || exit 1
                else
                    cp -f /tmp/my.cnf $my_cnf || exit 1
                    rm -rf $mysql_datadir/ib_log* $mysql_datadir/mysqld.pid $mysql_datadir/cmon $mysql_datadir/dcps
                fi
                rm -f /tmp/my.cnf
            fi
            ;;
        'redhat')
            install_packages="yum -y install mysql-server mysql"
            update_repo="yum update"
            mysql_basedir=/usr
            mysql_datadir=/var/lib/mysql
            stop_mysql=""
            start_mysql="service mysqld start"
            chkconfig="chkconfig --levels 235 mysqld on"
            mysql_socket="/var/lib/mysql/mysql.sock"

            if [[ ! -z $rhel_version ]]; then
                case "$rhel_version" in
                    7|8|9)
                        install_packages="yum -y install mariadb-server"
                        [[ -n $use_existing_mysql ]] && install_packages=""
                        ;;
                    *)
                        log_msg "Unknown/Unsupported Centos/Red Hat version $rhel_version"
                        exit 1
                        ;;
                esac
            fi

            if [[ -z ${OFFLINE+x} ]]; then
                if ! ask "=> Do $update_repo? (y/N): " "n"; then
                    $update_repo
                fi
            fi

            if [[ -n $install_packages ]]; then
                $install_packages
                [[ $? -ne 0 ]] && log_msg "Installing packages ${install_packages}, failed" && exit 1
            fi

            if [[ ! -z $rhel_version ]]; then
                case "$rhel_version" in
                    7|8|9)
                        yum list installed | grep -q mariadb-server
                        if [[ $? -eq 0 ]]; then
                            start_mysql="service mariadb start"
                            [[ ! -z $ORACLE ]] && start_mysql="systemctl start mariadb"
                            chkconfig="chkconfig --levels 235 mariadb on"
                        fi
                        ;;
                esac
            fi
            # workaround for mysql 8, not safe
            $(yum list installed | grep mysql | grep -q mysql80)
            if [[ $? -eq 0 ]]; then
                mysqld8="mysqld --initialize-insecure --user=mysql --basedir=/usr --datadir=/var/lib/mysql"
                $mysqld8
            fi
            $chkconfig
            ;;
    esac
    echo -e "\n=> Starting database. This may take a couple of minutes. Do NOT press any key."
    $start_mysql
    [[ $? -ne 0 ]] && log_msg "Failed to start the database server. ..." && exit 1

    log_msg "Securing the MySQL Server ..."
    log_msg "!! In order to complete the installation you need to set a MySQL root password !!"
    log_msg "Supported special password characters: ~!@#$%^&*()_+{}<>?"
    [[ -z $S9S_ROOT_PASSWORD ]] && read -n 1 -s -r -p "=> Press any key to proceed ..."
    echo ""

    case "${os_codename}" in
        'focal'|'disco'|'bionic'|'xenial'|'jammy'|'noble')
            $mysql_basedir/bin/mysql -uroot -P${db_port} -e "ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password BY ''"
            ;;
    esac

    if [[ -z ${S9S_CMON_PASSWORD} ]]; then
        [[ -e /var/lib/mysql/mysql.sock ]] && mysql_secure_installation --socket="/var/lib/mysql/mysql.sock" || mysql_secure_installation
        [[ $? -ne 0 ]] && log_msg "Unable to secure the MySQL server running mysql_secure_installation, exiting ..." && exit 1
        echo -e "\n=> Please enter the MySQL root password that was set to continue!"
        until set_root_password; do
            log_msg ""
            log_msg "Password mismatch! Try again."
            sleep 1
        done
    else
        log_msg "!! Setting MySQL root user password !!"
        [[ -e /var/lib/mysql/mysql.sock ]] && $mysql_basedir/bin/mysqladmin --socket="/var/lib/mysql/mysql.sock" -uroot password "${S9S_ROOT_PASSWORD}" || $mysql_basedir/bin/mysqladmin -uroot password "${S9S_ROOT_PASSWORD}"
        log_msg "!! Please run mysql_secure_installation after the setup !!"
    fi
}

configure_database_server() {
    find_mysql

    if [[ $root_password == "" ]] || [[ -z $root_password ]]; then
        IFS="" read -s -p "=> Enter your MySQL root user's password: " x
        [[ ! -z $x ]] && root_password="$x"
    fi

    $mysql_bin -uroot -p''"${root_password}"'' -P${db_port} -e "SELECT USER();" &>/dev/null
    if [[ $? -ne 0 ]]; then
        log_msg "Cannot Connect! Try again."
        IFS="" read -s -p "=> Enter your MySQL root user's password: " x
        [[ ! -z $x ]] && root_password="$x"
        log_msg ""
    fi

    log_msg "Set a password for ClusterControl's MySQL user (cmon) [${cmon_password}]"
    log_msg "Supported special characters: ~!@#$%^&*()_+{}<>?"
    until set_cmon_password; do
        log_msg ""
        log_msg "Password mismatch! Try again."
        sleep 1
    done

    cat > /tmp/ui.sql << EOF
BEGIN;
CREATE USER 'cmon'@'localhost' identified by '${cmon_password}';
GRANT ALL PRIVILEGES ON *.* to 'cmon'@'localhost' WITH GRANT OPTION;
CREATE USER 'cmon'@'127.0.0.1' identified by '${cmon_password}';
GRANT ALL PRIVILEGES ON *.* to 'cmon'@'127.0.0.1' WITH GRANT OPTION;
CREATE USER 'cmon'@'${host}' identified by '${cmon_password}';
GRANT ALL PRIVILEGES ON *.* to 'cmon'@'${host}' WITH GRANT OPTION;
COMMIT;
EOF

    log_msg "Creating the MySQL cmon user ..."
    if [[ -z $use_existing_mysql ]]; then
        $mysql_bin -uroot -P${db_port} -p''"${root_password}"'' < /tmp/ui.sql
    else
        cat > /tmp/drop.sql << EOF
DROP USER 'cmon'@'localhost';
DROP USER 'cmon'@'127.0.0.1';
DROP USER 'cmon'@'${host}';
EOF
        $mysql_bin -f -uroot -P${db_port} -p''"${root_password}"'' < /tmp/drop.sql &>/dev/null
        [[ $? -ne 0 ]] && log_msg "Failed to drop cmon user! ..." && exit 1
        rm -f /tmp/drop.sql
        $mysql_bin -f -uroot -P${db_port} -p''"${root_password}"'' < /tmp/ui.sql &>/dev/null
    fi
    [[ $? -ne 0 ]] && log_msg "Failed to add cmon user! ..." && exit 1
    rm -f /tmp/ui.sql
}

check_emailaddress() {
    if [[ "$1" =~ ^[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Za-z]{2,4}$ ]]; then
        return 0
    else
        log_msg "Invalid email address"
        return 1
    fi
}

set_cmon_password() {
    [[ ! -z $S9S_CMON_PASSWORD ]] && return 0
    IFS="" read -s -p "=> Enter a CMON user password: " x
    if [[ -z $x ]]; then
        log_msg "The password cannot be blank. Try again."
        IFS="" read -s -p "=> Enter a CMON user password: " x
    fi
    cmon_password="$x"
    log_msg ""
    IFS="" read -s -p "=> Enter the CMON user password again: " x
    if [[ "$cmon_password" == "$x" ]]; then
        return 0
    else
        return 1
    fi
}

set_root_password() {
    [[ ! -z $S9S_ROOT_PASSWORD ]] && return 0
    IFS="" read -s -p "=> Enter the MySQL root password: " x
    while [[ -z $x ]]; do
        log_msg "The password cannot be blank. Try again."
        IFS="" read -s -p "=> Enter the MySQL root password: " x
    done
    root_password="$x"
    log_msg ""
    IFS="" read -s -p "=> Enter the MySQL root password again: " x
    if [[ "$root_password" == "$x" ]]; then
        return 0
    else
        return 1
    fi
}

set_admin_password() {
    [[ ! -z $S9S_ADMIN_USER_PASSWORD ]] && return 0
    IFS="" read -s -p "Enter the admin user password: " x
    while [[ -z $x ]]; do
        log_msg "The password cannot be blank. Try again."
        IFS="" read -s -p "Enter the admin user password: " x
    done
    admin_user_password="$x"
    log_msg ""
    IFS="" read -s -p "Enter the admin user password again: " x
    if [[ "$admin_user_password" == "$x" ]]; then
        return 0
    else
        return 1
    fi
}

install_controller() {
    log_msg "Installing ClusterControl Controller ..."
    cmon_controller="clustercontrol-controller"
    cmon_basedir="/usr"
    [[ ! -z ${CONTROLLER_BUILD} ]] && cmon_controller=${CONTROLLER_BUILD}
    if [[ $dist == "redhat" ]]; then
        case "$rhel_version" in
            9)
                if [[ -z ${OFFLINE+x} ]]; then
                    if [[ -f /etc/almalinux-release ]] || [[ -f /etc/rocky-release ]]; then
                        dnf config-manager --set-enabled crb
                        dnf -y install epel-release
                    elif [[ -f /etc/centos-release ]]; then
                        dnf config-manager --set-enabled crb
                        dnf -y install epel-release epel-next-release
                    else
                        # assume RHEL 9 ...
                        subscription-manager repos --enable codeready-builder-for-rhel-9-$(arch)-rpms
                        dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-9.noarch.rpm
                        [[ $? -ne 0 ]] && setup_php7_redhat
                    fi
                fi
                ;;
            8)
                if [[ -z ${OFFLINE+x} ]]; then
                    if [[ -f /etc/almalinux-release ]] || [[ -f /etc/rocky-release ]]; then
                        dnf config-manager --set-enabled powertools
                        dnf -y install epel-release
                    elif [[ -f /etc/centos-release ]]; then
                        dnf config-manager --set-enabled powertools
                        dnf -y install epel-release epel-next-release
                    else
                        # assume RHEL 8 ...
                        subscription-manager repos --enable codeready-builder-for-rhel-8-$(arch)-rpms
                        dnf -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-8.noarch.rpm
                    fi
                fi
                ;;
            7)
                if [[ -z ${OFFLINE+x} ]]; then
                    if [[ -f /etc/centos-release ]]; then
                        yum -y install epel-release
                    elif [[ -f /etc/redhat-release ]]; then
                        subscription-manager repos --enable rhel-*-optional-rpms \
                            --enable rhel-*-extras-rpms \
                            --enable rhel-ha-for-rhel-*-server-rpms
                        yum -y install https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
                    fi
                fi
                ;;
            esac
        # fix CMON API port for SELinux
        log_msg "Adding CMON API port 19501 for SELinux ..."
        semanage port -a -t http_port_t -p tcp 19501 &>/dev/null
        log_msg "Adding CMON port 19510 for events ..."
        semanage port -a -t http_port_t -p tcp 19510 &>/dev/null
        log_msg "Adding CMON port 19518 for clouds ..."
        semanage port -a -t http_port_t -p tcp 19518 &>/dev/null
        # enable httpd for network connections just in case it's off by default
        log_msg "Setting httpd_can_network_connect to 'on' for SELinux ..."
        semanage boolean --modify --on httpd_can_network_connect &>/dev/null

        enable_service="chkconfig --levels 235 cmon on"
        yum -y install $cmon_controller
        [[ $? -ne 0 ]] && exit 1
    elif [[ $dist == "debian" ]]; then
        enable_service="update-rc.d cmon defaults"
        waitForLocks
        apt-get -y install $cmon_controller
        [[ $? -ne 0 ]] && exit 1
    fi

    cat >> /etc/default/cmon << EOF
# New events client http callback as of v1.4.2!
EVENTS_CLIENT="http://127.0.0.1:${cmon_events_port}"
CLOUD_SERVICE="http://127.0.0.1:${cmon_cloud_port}"
EOF

    # use the cmon token for the global rcp_token
    rpc_key=${cc_api_token}

    # import cmon schema using cmon --init
    # rm /etc/cmon/cnf that came with the package
    rm -f /etc/cmon.cnf
    cmon --init \
        --mysql-hostname="127.0.0.1" \
        --mysql-port="${db_port}" \
        --mysql-username="${cmon_user}" \
        --mysql-password="${cmon_password}" \
        --mysql-database="cmon" \
        --hostname="${host}" \
        --rpc-token="${rpc_key}" \
        --controller-id="clustercontrol"
    [[ $? -ne 0 ]] && log_msg "Unable to init cmon! Exiting ..." && exit 1

    $enable_service
    log_msg "Starting the Controller process."
    if [[ $systemd == 1 ]]; then
        systemctl restart cmon
        systemctl enable cmon
    else
        service cmon restart
    fi

    if [[ $dist == "redhat" ]]; then
        if [[ $rhel_version = "7" ]]; then
            yum install -y ntp ntpdate
            chkconfig ntpd on
            ntpdate pool.ntp.org
            service ntpd start
        fi
    fi
}

install_s9s_commandline() {
    s9s_tools=s9s-tools
    [[ ! -z ${S9S_TOOLS_BUILD} ]] && s9s_tools=${S9S_TOOLS_BUILD}
    if [[ $dist == "redhat" ]]; then
        yum -y install $s9s_tools
    elif [[ $dist == "debian" ]]; then
        waitForLocks
        apt-get -y install $s9s_tools
    fi
    [[ $? -ne 0 ]] && log_msg "Unable to install s9s-tools" && exit 1

    echo "=> Waiting 60s until the CMON Controller completes its startup cycle ..."
    sleep 60 # wait for cmon to start on slower systems

    local email="${S9S_ADMIN_EMAIL:-##__EMAIL__##}"
    if [[ "$email" != *"@"* ]]; then
        email=""
    fi
    export S9S_USER_CONFIG=/tmp/ccsetup.conf
    log_msg "Create temporary cc setup user ..."
    s9s user --create --new-password=admin --group=admins --email-address="${email}" --controller="https://localhost:9501" ccsetup
    if [[ $? -ne 0 ]]; then
        log_msg "*** Unable to create a 'ccsetup' user! ***"
        exit 1
    fi
    unset S9S_USER_CONFIG

    log_msg "*** Restarting the Controller process to generate CMON API rpc_tls files."
    if [[ $systemd == 1 ]]; then
        systemctl restart cmon
    else
        service cmon restart
    fi
}

log_msg() {
    LAST_MSG="$1"
    echo "$(date +'%Y-%m-%d %H:%M:%S %Z') -- ${LAST_MSG}"
}

track_install_init() {
    [[ -n ${INSTALLATION_PROGRESS} ]] && wget -qO- --no-check-certificate --post-data="container=${CONTAINER}&email=##__EMAIL__##&uuid=${cc_api_token}&version=${VERSION}&os=${OS}&step=1" https://severalnines.com/service/install_log.php &>/dev/null
}

track_install() {
    [[ -n ${INSTALLATION_PROGESS} ]] && wget -qO- --no-check-certificate --post-data="uuid=${cc_api_token}&step=${1}" https://severalnines.com/service/install_log.php &>/dev/null
}

checkLock() {
    if command -v fuser >/dev/null 2>/dev/null; then
        fuser $@ 2>/dev/null >/dev/null
        return $?
    fi
    # fuser (psmisc) not installed, go with lsof
    if [[ "`lsof $@ 2>/dev/null >/dev/null`x" != "x" ]]; then
        return 0
    fi
    return 1
}

waitForLocks() {
    if checkLock /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock; then
        echo -n "=> Waiting for APT/DPKG locks."
    else
        return
    fi
    while checkLock /var/lib/dpkg/lock /var/lib/dpkg/lock-frontend /var/lib/apt/lists/lock /var/cache/apt/archives/lock; do
        echo -n .
        sleep 1
    done
    echo .
}

cleanup() {

    if [[ ! -z ${SEND_DIAGNOSTICS} ]]; then
        [[ $(command -v cmon) ]] && VERSION=$(cmon --version | awk '/version/ {print $3}')
        if [[ $CONTAINER != "" ]]; then
            UUID=$(hostname | md5sum | cut -d' ' -f1)
        else
            UUID=$(dmidecode --string system-uuid 2>/dev/null | sed 's#-##g' | sha256sum | awk '{print $1}')
        fi
        OS=$(cat /proc/version)
        MEM=$(free -m | awk '/Mem:/ { print "T:" $2, "F:" $4}')
        if [[ -z $PYTHON3 ]]; then
            OS=$(python -c "import sys,urllib; print urllib.quote('${OS}')")
            MEM=$(python -c "import sys,urllib; print urllib.quote('${MEM}')")
            LAST_MSG=$(python -c "import sys,urllib; print urllib.quote('${LAST_MSG}')")
        else
            OS=$(python -c "import sys,urllib.parse; print(urllib.parse.quote('${OS}'))")
            MEM=$(python -c "import sys,urllib.parse; print(urllib.parse.quote('${MEM}'))")
            LAST_MSG=$(python -c "import sys,urllib.parse; print(urllib.parse.quote('${LAST_MSG}'))")
        fi

        wget -qO- --post-data="version=${VERSION:=NA}&uuid=${UUID}&os=${OS}&mem=${MEM}&rc=${INSTALLATION_STATUS}&msg=${LAST_MSG}&container=${CONTAINER}" https://severalnines.com/service/diag.php &>/dev/null

        [[ ${INSTALLATION_STATUS} == "1" ]] && echo "Please contact Severalnines support at http://support.severalnines.com if you have installation issues that cannot be resolved."
    fi
}

check_os() {
    dist="Unknown"
    regex_lsb="Description:[[:space:]]*([^ ]*)"
    regex_etc="/etc/(.*)[-_]"
    systemd=0
    [[ $(readlink /sbin/init) == *"systemd"* ]] && systemd=1

    # install lsb-release on debian|ubuntu
    if apt-get --version >/dev/null 2>/dev/null; then
        log_msg "Installing lsb-release ..."
        if [[ -z ${OFFLINE+x} ]]; then
            waitForLocks
            apt-get update -qq
        fi
        apt-get install -yq lsb-release
    fi

    if command -v lsb_release &>/dev/null; then
        do_lsb
        [[ $? -ne 0 ]] && do_release_file
    else
        do_release_file
    fi

    dist=$(echo $dist | tr '[:upper:]' '[:lower:]')
    [[ ! -z $CENTOS ]] && dist="centos"
    case $dist in
        debian) dist="debian";;
        ubuntu) dist="debian";;
        red)    dist="redhat";;
        redhat) dist="redhat";;
        centos) dist="redhat";;
        fedora) dist="redhat";;
        oracle) dist="redhat";;
        system)
            dist="redhat" # amazon ami
            log_msg "This distro is not supported! Supported OS, https://severalnines.com/docs/requirements.html#operating-system"
            exit 1
            ;; # amazon ami
        *) log_msg "This script couldn't detect a supported distriution (dists parsed: ''$dist')."; ask_generic_distro
    esac
}

create_cert() {

    local domain=*.severalnines.local
    local commonname=$domain
    local san=dev.severalnines.local
    local country=SE
    local state=Stockholm
    local locality=Stockholm
    local organization='Severalnines AB'
    local organizationalunit=Severalnines
    local email=support@severalnines.com
    local keylength=2048
    local expires=1825
    local keyname=server.key
    local certname=server.crt
    local csrname=server.csr

    cat > /tmp/v3.ext << EOF
basicConstraints = CA:FALSE
#authorityKeyIdentifier=keyid,issuer
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = clientAuth, serverAuth
subjectAltName = DNS:${san}
EOF

    echo "==> Generating tls certificate for $domain"
    # ubunutu 18.0x workaround
    touch $HOME/.rnd
    openssl genrsa -out $keyname $keylength

    openssl req -new -key $keyname -out $csrname \
        -addext "subjectAltName = DNS:${san}" \
        -subj "/C=$country/ST=$state/L=$locality/O=$organization/OU=$organizationalunit/CN=$commonname/emailAddress=$email" &>/dev/null

        if [[ $? -ne 0 ]]; then
        # centos 6 -addtext is not avaiable
        openssl req -new -key $keyname -out $csrname \
            -subj "/C=$country/ST=$state/L=$locality/O=$organization/OU=$organizationalunit/CN=$commonname/emailAddress=$email"
    fi
    openssl x509 -req -extfile /tmp/v3.ext -days $expires -sha256 -in $csrname -signkey $keyname -out $certname

    rm -f /tmp/v3.ext
    cd - &>/dev/null
}

main() {
    # check distro
    check_os
    if [[ "${dist}" == "redhat" ]]; then
        command -v chkconfig || dnf -y install chkconfig
    fi

    # trap cleanup EXIT
    INSTALLATION_STATUS=1
    INSTALLATION_PROGRESS=1
    LAST_MSG=""
    repo_http_protocol="http"
    [[ ! -z $REPO_USE_TLS ]] && repo_http_protocol="https"
    message="This script will add Severalnines repository server for deb and rpm packages and  \
        \ninstall the ClusterControl Web Applicaiton and Controller. \
        \nAn Apache and MySQL server will also be installed. An existing MySQL Server on this host can be used."

    [[ `whoami` != "root" ]] && echo -e "Do: sudo $(basename $0) or run as root\n" && echo -e "$message" && exit 1

    # Check if the OS is a 64 bit one. If it's a 32 bit, the installation fails
    # with a non'very descriptive message
    if [[ "$(uname -m)" != 'x86_64'  ]]; then
        log_msg "ClusterControl is only compatible with x86_64 systems" && exit 1
    fi

    if [[ ! -z $NO_INET ]]; then
        log_msg ""
        log_msg "Detected NO_INET is set, i.e., OFFLINE install."
        log_msg "Please follow the instructions in the online manual, https://severalnines.com/docs/installation.html#offline-installation"
        exit 0
    fi

    while [[ $# > 0  ]]; do
        arg="$1"
        case "$arg" in
            -v|--verbose)
                PROMPT_USER=1
                shift
                ;;
            -u|--uninstall)
                uninstall_packages
                exit 0
                ;;
            -r|--release)
                ;;
            -e|--edge)
                USE_REPO="edge"
                ;;
            -1|--version1)
                # install only v1 of the frontend
                # deprecated / not available any longer!
                echo "CCv1 is no longer available!! Exiting ..." && exit 1
                ;;
            -2|--version2)
                # install only v2 of the frontend
                # this is the default UI for now. later mcc should be the default to use
                CCVERSION=2
                ;;
            -3|--version3)
                # install CC Ops-C / multi cmon controller support
                # mcc should be default
                CCVERSION=3
                ;;
            *)
                log_msg "Unknown option $arg"
                exit 1
                ;;
        esac
        shift
    done

    # install CCv2 by default
    cc_version=${CCVERSION:-2}

    echo "!!"
    log_msg "Only RHEL/RockyLinux/AlmaLinux 8|9, Debian 11|12, Ubuntu 20.04|22.04|24.04 LTS versions are supported"

    # FREE_DISKSPACE=$(df -hP $PWD | awk '/[0-9]%/{print $(NF-2)}' | cut -d'G' -f1 | awk -F '.' '{ print $1 }')
    # REQ_DISKSPACE=5
    # if [[ $FREE_DISKSPACE -lt $REQ_DISKSPACE ]]; then
    #     log_msg "** Less than ${REQ_DISKSPACE}GB disk space left. Stopping ..."
    #     exit 1
    # fi
    
    cc_api_token=$(cat /proc/sys/kernel/random/uuid | sha1sum | cut -f1 -d' ')
    CONTAINER="NA"
    [[ -f /.dockerenv ]] && CONTAINER="docker"
    grep -qa container=lxc /proc/1/environ &>/dev/null
    [[ $? -eq 0 ]] && CONTAINER="lxc"

    running_mysql=1
    if [[ -f /usr/libexec/mysqld || -f /usr/sbin/mysqld ]]; then
        ps -C mysqld &>/dev/null
        running_mysql=$?
    elif [[ -f /usr/sbin/mariadbd ]]; then
        ps -C mariadbd &>/dev/null
        running_mysql=$?
    fi

    if [[ $running_mysql -eq 1 ]]; then
        MEM_TOTAL=$(free -m | awk '/Mem:/ { print $2}')
        MEM_FREE=$(free -m | awk '/Mem:/ { print $ 4}')
        # default 512M
        if (( ${MEM_TOTAL} < 1500 )); then
            log_msg "Minimum system requirements: 2GB+ RAM, 2+ CPU cores"
            log_msg "Server Memory: ${MEM_TOTAL}M total, ${MEM_FREE}M free"
            INNODB_BUFFER_POOL_SIZE=${INNODB_BUFFER_POOL_SIZE:-512}
        else
            SIZE=$((50*${MEM_TOTAL}/100))
            INNODB_BUFFER_POOL_SIZE=${INNODB_BUFFER_POOL_SIZE:-${SIZE}}
            log_msg "System RAM is > 1.5G"
            log_msg "Setting MySQL innodb_buffer_pool_size to 50% of system RAM"
        fi
        log_msg "MySQL innodb_buffer_pool_size set to ${INNODB_BUFFER_POOL_SIZE}M"
        echo ""

        MIN_FREE_MEMORY=${MIN_FREE_MEMORY:-100}
        if (( ${INNODB_BUFFER_POOL_SIZE} + ${MIN_FREE_MEMORY} > ${MEM_FREE} )); then
            log_msg "You do not have enough free memory ${MEM_FREE}M available to set innodb_buffer_pool_size=${INNODB_BUFFER_POOL_SIZE}M"
            log_msg "Need at least 100M or more free memory in addition to what innodb_buffer_pool_size will allocate."
            if [[ -z $S9S_CMON_PASSWORD ]]; then
                read -p "=> Enter new innodb_buffer_pool_size (in MB, e.g, 512): " x
                [[ ! -z $x ]] && INNODB_BUFFER_POOL_SIZE=$x
                log_msg "Using new innodb_buffer_pool_size ${INNODB_BUFFER_POOL_SIZE}M"
                echo ""
            else
                exit 1
            fi
        fi
    fi

    log_msg "Severalnines would like your help improving our installation process."
    log_msg "Information such as OS, memory and install success helps us improve how we onboard our users."
    log_msg "None of the collected information identifies you personally."
    log_msg "!!"
    if ask_p "=> Would you like to help us by sending installation log after the installation? (Y/n): " "y"; then
        SEND_DIAGNOSTICS=1
    fi
    echo ""

    [[ ! -z $message ]] && echo -e $message
    echo ""

    until set_root_password; do
        log_msg ""
        log_msg "Password mismatch! Try again."
        sleep 1
    done
    [ -z ${root_password+x} ] || S9S_ROOT_PASSWORD="${root_password}"
    echo ""
    until set_cmon_password; do
        log_msg ""
        log_msg "Password mismatch! Try again."
        sleep 1
    done
    [ -z ${cmon_password+x} ] || S9S_CMON_PASSWORD="${cmon_password}"

    if [[ "$dist" == "debian" ]]; then
        waitForLocks
        log_msg "Installing required packages ..."
        apt-get install -yq wget bc gnupg dmidecode
        case "${os_codename}" in
            'focal'|'bionic'|'jammy'|'noble')
                log_msg "Installing python ..."
                apt-get install -yq python3
                update-alternatives --install /usr/bin/python python /usr/bin/python3 1
                ;;
            *)
                log_msg "Installing python ..."
                apt-get install -yq python
                ;;
        esac
        python --version | grep -q 3.
        [[ $? -eq 0 ]] && PYTHON3=1

        if ! command -v add-apt-repository &>/dev/null; then
            case "${os_codename}" in
                'stretch'|'buster'|'bullseye'|'bookworm'|'xenial'|'focal'|'jammy'|'noble')
                    log_msg "Installing software-properties-common ..."
                    apt-get install -yq software-properties-common
                    ;;
                *)
                    log_msg "Installing python-software-properties ..."
                    apt-get install -yq python-software-properties
                    ;;
            esac
        fi
    fi

    if [[ "$dist" == "redhat" ]]; then
        log_msg "Installing required packages ..."
        yum install -yq wget dmidecode hostname
        log_msg "Installing python ..."
        if [[ $rhel_version == "8" ]]; then
            yum install -y python36
            alternatives --set python /usr/bin/python3
        else
            yum install -y python
        fi
        python --version | grep -q 3.
        [[ $? -eq 0 ]] && PYTHON3=1
    fi

    wwwroot="/var/www/html"
    if [[ "$dist" == "debian" ]]; then
        wwwroot="/var/www"

        distro_id=$(lsb_release -s -i)
        distro_release=$(lsb_release -s -r)
        if [[ $? -eq 0 ]]; then
            distro_release=${distro_release%%.*}
            # Apache 2.4 uses new config
            if [[ ${distro_id} == "Ubuntu" ]]; then
                if (( $(echo "$distro_release > 12" | bc) )); then
                    use_apache24=1
                fi
            elif [[ ${distro_id} == "Debian" ]]; then
                if (( $(echo "$distro_release > 7" | bc) )); then
                    use_apache24=1
                fi
            fi
        else
            log_msg "Unable to determine distro release number ..."
            log_msg "Assuming > apache 2.4..."
            use_apache24=1
        fi
        [[ ! -z $use_apache24 ]] && wwwroot="/var/www/html"
    fi

    ip=($(hostname -I)) || ip=($(hostname -i))
    host="${HOST:-${ip[0]}}"

    [[ ${#ip[@]} > 1 && -z ${HOST} ]] && message="$message\nNOTE: Detected more than one IP: ${ip[@]}\nUsing hostname ${host} or do 'export HOST=<hostname>' to explicitly set a host"
    echo -e $message

    if command -v dig &>/dev/null; then
        echo ""
        echo "Determining network interfaces ..."
        ext_ip=$(dig +short myip.opendns.com @resolver1.opendns.com 2>/dev/null)
        log_msg "Web application IP => https://${ext_ip}"
    fi

    if [[ -z ${HOST} ]]; then
        echo ""
        if ! ask_p "=> The CMON Controller's hostname will be set to $host. Do you want to change it? (y/N): " "n"; then
            read -p "=> Enter the hostname: " x
            [[ ! -z $x ]] && host="$x"
        fi
    fi
    log_msg "Using hostname $host"

    db_port=${S9S_DB_PORT:-3306}
    cmon_user=${S9S_CMON_USER:-"cmon"}
    cmon_password=${S9S_CMON_PASSWORD:-"cmon"}
    cmon_events_port=${S9S_EVENTS_PORT:-9510}
    cmon_cloud_port=${S9S_CLOUD_PORT:-9518}
    root_password=${S9S_ROOT_PASSWORD:-""}

    echo ""
    log_msg "Using web document root $wwwroot"
    mkdir -p $wwwroot

    install_cmon=0
    if ask "=> Install the ClusterControl Controller? (Y/n): " "y"; then
        install_cmon=1
        if [[ -z ${S9S_CMON_PASSWORD} && -f /etc/cmon.cnf ]]; then
            log_msg "An existing Controller installation detected!"
            log_msg "A re-installation of the Controller will overwrite the /etc/cmon.cnf file"
            if ask_p "=> Install the Controller? (y/N): " "n"; then
                install_cmon=0
            fi
        fi
    fi

    if [[ $running_mysql -eq 0  ]]; then
        if ask_p "=> Detected a running MySQL server. Should I use your existing MySQL server? (Y/n): " "y"; then
            use_existing_mysql=1
        fi
    fi

    if [[ -z $use_existing_mysql ]]; then
        log_msg "Install the default distro MySQL Server ..."
    fi

    log_msg "Installing the ClusterControl Web Application ..."
    # install web app
    install_frontend
    track_install_init
    log_msg "Installing MySQL server ..."
    track_install "2"
    install_database_server
    log_msg "Configuring the MySQL server ..."
    track_install "3"
    configure_database_server

    track_install "4"
    if [[ ${cc_version} == "2" ]]; then
        log_msg "Installing Web / Apache server ..."
        install_web_server
        configure_ccv2_web
        log_msg "ClusterControl v2 frontend installed ..."
    fi

    # Install Controller
    if [[ $install_cmon -eq 1 ]]; then
        track_install "5"
        install_controller
        install_s9s_commandline
        # start events and ssh services
        start_cmon_services
        # restart the apache server - this is needed for the rpc_tls.crt
        [[ -f /var/lib/cmon/ca/cmon/rpc_tls.crt ]] || sleep 5
        if [[ ${cc_version} == "2" ]]; then
            log_msg "Restarting Apache server ..."
            $restart_apache || log_msg "Unable to restart the Apache Server ..."
        fi
    fi

    if [[ ${cc_version} == "3" ]]; then
        # Setup CC MCC / Ops-C
        log_msg "Configuring ClusterControl MCC / Ops-C ..."
        configure_mcc
        log_msg "ClusterControl MCC / Ops-C frontend installed ..."
    fi

    # success
    INSTALLATION_STATUS=0
    [[ ! -z ${ext_ip} ]] && host="${ext_ip}"
    log_msg "ClusterControl installation completed!"
    track_install "6"
    echo "Open your web browser to https://${host} to start using ClusterControl."
    echo "If you want to uninstall ClusterControl then please follow the instructions here, https://severalnines.com/docs/administration.html#uninstall"
    exit 0
}

main "$@"