#!/usr/bin/env bash

# MariaDB Installer
# Min. Requirement  : GNU/Linux Ubuntu 18.04
# Last Build        : 13/02/2022
# Author            : MasEDI.Net (me@masedi.net)
# Since Version     : 1.0.0

# Include helper functions.
if [[ "$(type -t run)" != "function" ]]; then
    BASE_DIR=$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )
    # shellcheck disable=SC1091
    . "${BASE_DIR}/utils.sh"

    # Make sure only root can run this installer script.
    requires_root "$@"

    # Make sure only supported distribution can run this installer script.
    preflight_system_check
fi

##
# Add MariaDB Repository.
##
function add_mariadb_repo() {
    echo "Adding MariaDB repository..."

    MYSQL_SERVER=${MYSQL_SERVER:-"mariadb"}
    MYSQL_VERSION=${MYSQL_VERSION:-"11.1"}

    # Fallback to oldest version if OS release is not supported.
    case "${RELEASE_NAME}" in
        jessie)
            MYSQL_VERSION="10.5"
        ;;
        bionic)
           MYSQL_VERSION="11.1"
        ;;
    esac

    if [[ "${MYSQL_REPO_MIRROR_URL}x" == "x" ]]; then
        # Add MariaDB official repo.
        MARIADB_REPO_SETUP_URL="https://downloads.mariadb.com/MariaDB/mariadb_repo_setup"

        if curl -sLI "${MARIADB_REPO_SETUP_URL}" | grep -q "HTTP/[.12]* [2].."; then
            run curl -sSL -o "${BUILD_DIR}/mariadb_repo_setup" "${MARIADB_REPO_SETUP_URL}" && \
            run bash "${BUILD_DIR}/mariadb_repo_setup" --mariadb-server-version="mariadb-${MYSQL_VERSION}" \
                --os-type="${DISTRIB_NAME}" --os-version="${RELEASE_NAME}" --skip-maxscale --skip-tools && \
            run apt-get update -q -y
        else
            info "MariaDB repo installer not found, trying to use pre-downloaded script."
            run bash "${BASE_DIR}/mariadb_repo_setup" --mariadb-server-version="mariadb-${MYSQL_VERSION}" \
                --os-type="${DISTRIB_NAME}" --os-version="${RELEASE_NAME}" --skip-maxscale --skip-tools && \
            run apt-get update -q -y
        fi
    else
        # Add MariaDB mirror repo.
        local MARIADB_REPO_URL="${MYSQL_REPO_MIRROR_URL}/repo/${MYSQL_VERSION}/${DISTRIB_NAME}"

        if curl -sLI "${MARIADB_REPO_URL}/dists/${RELEASE_NAME}/Release" | grep -q "HTTP/[.12]* [2].."; then
            run bash -c "curl -fsSL https://mariadb.org/mariadb_release_signing_key.pgp | gpg --dearmor --yes -o /usr/share/keyrings/mariadb-keyring.gpg" && \
            run chmod 644 "/usr/share/keyrings/mariadb-keyring.gpg" && \
            run touch "/etc/apt/sources.list.d/mariadb.list" && \
            run bash -c "echo 'deb [signed-by=/usr/share/keyrings/mariadb-keyring.gpg] ${MARIADB_REPO_URL} ${RELEASE_NAME} main' > /etc/apt/sources.list.d/mariadb.list" && \
            run bash -c "echo '#deb-src [signed-by=/usr/share/keyrings/mariadb-keyring.gpg] ${MARIADB_REPO_URL} ${RELEASE_NAME} main' >> /etc/apt/sources.list.d/mariadb.list" && \
            run apt-get update --allow-releaseinfo-change -q -y
        else
            error "MariaDB ${MYSQL_VERSION} release at mirror ${MYSQL_REPO_MIRROR_URL} not found."
        fi
    fi
}

##
# Install MariaDB (MySQL drop-in).
##
function init_mariadb_install() {
    if [[ "${AUTO_INSTALL}" == true ]]; then
        if [[ "${INSTALL_MYSQL}" == true ]]; then
            DO_INSTALL_MYSQL="y"
        else
            DO_INSTALL_MYSQL="n"
        fi
    else
        while [[ "${DO_INSTALL_MYSQL}" != y* && "${DO_INSTALL_MYSQL}" != n* ]]; do
            read -rp "Do you want to install MariaDB server? [y/n]: " -i y -e DO_INSTALL_MYSQL
        done
    fi

    # Do MariaDB server installation here...
    if [[ ${DO_INSTALL_MYSQL} == y* || ${DO_INSTALL_MYSQL} == Y* ]]; then
        # Add repository.
        add_mariadb_repo

        echo "Installing MariaDB (MySQL drop-in replacement) server..."

        # Install MariaDB
        run apt-get install -q -y libmariadb-dev libmariadb3 libmariadbclient18 mariadb-client mariadb-client-core \
            mariadb-common mariadb-server mariadb-server-core mariadb-backup

        # Configure MySQL installation.
        if [[ "${DRYRUN}" == true ]]; then
            info "MariaDB server installed in dry run mode."
        else
            if [[ -n $(command -v mysql) ]]; then
                if [[ ! -d /etc/mysql/conf.d ]]; then
                    run mkdir -p /etc/mysql/conf.d
                    run cp -fr etc/mysql/conf.d /etc/mysql/
                fi

                if [[ ! -d /etc/mysql/mariadb.conf.d ]]; then
                    run mkdir -p /etc/mysql/mariadb.conf.d
                    run cp -fr etc/mysql/mariadb.conf.d /etc/mysql/
                fi

                [[ ! -f /etc/mysql/mariadb.cnf ]] && run cp -f etc/mysql/mariadb.cnf /etc/mysql/
                [[ ! -f /etc/mysql/my.cnf ]] && run ln -s /etc/mysql/mariadb.cnf /etc/mysql/my.cnf
                [[ ! -f /etc/mysql/debian.cnf ]] && run cp -f etc/mysql/debian.cnf /etc/mysql/

                # Debian start service.
                if [[ ! -f /etc/mysql/debian-start || "${MYSQL_SECURE_INSTALL}" == true ]]; then
                    run cp -f etc/mysql/debian-start /etc/mysql/
                    run chmod ugo+x /etc/mysql/debian-start
                fi

                # MySQL init script.
                if [[ ! -f /etc/init.d/mysql ]]; then
                    run cp etc/init.d/mysql /etc/init.d/
                    run chmod ugo+x /etc/init.d/mysql
                fi

                # MariaDB init script.
                if [[ ! -f /etc/init.d/mariadb ]]; then
                    run cp etc/init.d/mariadb /etc/init.d/
                    run chmod ugo+x /etc/init.d/mariadb
                fi

                # Systemd script.
                [[ ! -f /lib/systemd/system/mariadb.service ]] && \
                    run cp etc/systemd/mariadb.service /lib/systemd/system/

                [[ ! -f /etc/systemd/system/multi-user.target.wants/mariadb.service && -f /lib/systemd/system/mariadb.service ]] && \
                    run ln -sf /lib/systemd/system/mariadb.service /etc/systemd/system/multi-user.target.wants/mariadb.service

                [[ ! -f /etc/systemd/system/mysqld.service && -f /lib/systemd/system/mariadb.service ]] && \
                    run ln -sf /lib/systemd/system/mariadb.service /etc/systemd/system/mysqld.service

                [[ ! -f /etc/systemd/system/mysql.service && -f /lib/systemd/system/mariadb.service ]] && \
                    run ln -sf /lib/systemd/system/mariadb.service /etc/systemd/system/mysql.service

                # Install default table.
                if [[ -n $(command -v mariadb-install-db) ]]; then
                    run mariadb-install-db && \
                    run chown -hR mysql:mysql /var/lib/mysql
                elif [[ -n $(command -v mysql_install_db) ]]; then
                    run mysql_install_db && \
                    run chown -hR mysql:mysql /var/lib/mysql
                else
                    error "Unable to secure MariaDB installation."
                fi

                # Trying to reload daemon.
                run systemctl daemon-reload

                # Unmask systemd service (?)
                run systemctl unmask mariadb.service

                # Enable MariaDB on startup.
                run systemctl enable mariadb.service

                # Restart MariaDB service daemon.
                run systemctl start mariadb.service

                ##
                # MariaDB secure installation
                # Ref: https://mariadb.com/kb/en/library/security-of-mariadb-root-account/
                #
                if [[ "${AUTO_INSTALL}" == true ]]; then
                    if [[ "${MYSQL_SECURE_INSTALL}" == true ]]; then
                        echo "Securing MariaDB Installation..."

                        # Ref: https://bertvv.github.io/notes-to-self/2015/11/16/automating-mysql_secure_installation/
                        MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD:-$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)}
                        local SQL_QUERY=""

                        # Setting the database root password.
                        SQL_QUERY="ALTER USER 'root'@'localhost' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}';"

                        # Delete anonymous users.
                        SQL_QUERY="${SQL_QUERY}
                                DELETE FROM mysql.user WHERE User='';"
                        
                        # Ensure the root user can not log in remotely.
                        SQL_QUERY="${SQL_QUERY}
                                DELETE FROM mysql.user WHERE User='root' AND Host NOT IN ('localhost', '127.0.0.1', '::1');"

                        # Remove the test database.
                        SQL_QUERY="${SQL_QUERY}
                                DROP DATABASE IF EXISTS test;
                                DELETE FROM mysql.db WHERE Db='test' OR Db='test\_%';"

                        # Flush the privileges tables.
                        SQL_QUERY="${SQL_QUERY}
                                FLUSH PRIVILEGES;"

                        # Root password is blank for newly installed MariaDB (MySQL).
                        if mariadb --user=root --password="${MYSQL_ROOT_PASSWORD}" -e "${SQL_QUERY}"; then
                            success "Securing MariaDB server installation has been done."
                        else
                            error "Unable to secure MariaDB server installation."
                        fi
                    fi
                else
                    if [[ "${MYSQL_SECURE_INSTALL}" == true ]]; then
                        while [[ "${DO_MYSQL_SECURE_INSTALL}" != "y" && "${DO_MYSQL_SECURE_INSTALL}" != "n" ]]; do
                            read -rp "Do you want to secure MariaDB installation? [y/n]: " -e DO_MYSQL_SECURE_INSTALL
                        done

                        if [[ "${DO_MYSQL_SECURE_INSTALL}" == y* || "${DO_MYSQL_SECURE_INSTALL}" == Y* ]]; then
                            if [[ -n $(command -v mariadb-secure-installation) ]]; then
                                run mariadb-secure-installation
                            elif [[ -n $(command -v mysql_secure_installation) ]]; then
                                run mysql_secure_installation
                            else
                                error "Unable to secure MariaDB installation."
                            fi
                        fi
                    fi
                fi
            fi

            if [[ $(pgrep -c mariadb) -gt 0 || -n $(command -v mysql) ]]; then
                success "MariaDB server installed successfully."

                # Allow remote client access
                allow_remote_client_access

                # Enable Mariabackup
                enable_mariabackup

                # Restart MariaDB (MySQL)
                run systemctl restart mariadb.service

                if [[ $(pgrep -c mariadb) -gt 0 ]]; then
                    success "MariaDB server configured successfully."
                elif [[ -n $(command -v mysql) || -n $(command -v mariadb) ]]; then
                    # Server died? try to start it.
                    run systemctl start mariadb.service

                    if [[ $(pgrep -c mariadb) -gt 0 ]]; then
                        success "MariaDB server configured successfully."
                    else
                        info "Something went wrong with MariaDB server configuration."
                    fi
                fi
            else
                info "Something went wrong with MariaDB server installation."
            fi
        fi
    else
        info "MariaDB installation skipped."
    fi
}

##
# Enable MariaDB Backup tool.
##
function enable_mariabackup() {
    echo ""
    echo "Mariabackup will be installed and enabled by default."
    echo "It is useful to backup and restore MySQL database."
    echo ""
    sleep 1

    export MARIABACKUP_USER=${MARIABACKUP_USER:-"lemperdb"}
    MARIABACKUP_PASS=${MARIABACKUP_PASS:-$(openssl rand -base64 64 | tr -dc 'a-zA-Z0-9' | fold -w 16 | head -n 1)}
    export MARIABACKUP_PASS

    #echo "Please enter your current MySQL root password to process!"
    until [[ "${MYSQL_ROOT_PASSWORD}" != "" ]]; do
        echo -n "MySQL root password: "; stty -echo; read -r MYSQL_ROOT_PASSWORD; stty echo; echo
    done
    export MYSQL_ROOT_PASSWORD

    # Create default LEMPer database user if not exists.
    if ! mariadb -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT User FROM mysql.user;" | grep -q "${MARIABACKUP_USER}"; then
        # Create mariabackup user.
        SQL_QUERY="CREATE USER '${MARIABACKUP_USER}'@'localhost' IDENTIFIED BY '${MARIABACKUP_PASS}';
                GRANT RELOAD, PROCESS, LOCK TABLES, REPLICATION CLIENT ON *.* TO '${MARIABACKUP_USER}'@'localhost';"

        run mariadb -u root -p"${MYSQL_ROOT_PASSWORD}" -e "${SQL_QUERY}"

        # Update my.cnf
        MARIABACKUP_CNF="###################################
# Custom optimization for LEMPer
# Mariabackup credential
#
[mariabackup]
user=${MARIABACKUP_USER}
password=${MARIABACKUP_PASS}
open_files_limit=65535
"

        if [[ -d /etc/mysql/mariadb.conf.d ]]; then
            run touch /etc/mysql/mariadb.conf.d/50-mariabackup.cnf
            run bash -c "echo '${MARIABACKUP_CNF}' > /etc/mysql/mariadb.conf.d/50-mariabackup.cnf"
        else
            run bash -c "echo -e '\n${MARIABACKUP_CNF}' >> /etc/mysql/my.cnf"
        fi

        # Save config.
        save_config -e "MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}\nMARIABACKUP_USERNAME=${MARIABACKUP_USER}\nMARIABACKUP_PASSWORD=${MARIABACKUP_PASS}"

        # Save log.
        save_log -e "MariaDB server credentials.\nMySQL Root Password: ${MYSQL_ROOT_PASSWORD}, MariaBackup DB Username: ${MARIABACKUP_USER}, MariaBackup DB Password: ${MARIABACKUP_PASS}\nSave this credential and use it to authenticate your MySQL database connection."
    else
        info "It seems that user '${MARIABACKUP_USER}' already exists. You can add mariabackup user manually!"
    fi
}

##
# Allow remote client access
# You need to add the following query to the client account
#CREATE USER 'username'@'ip_address' IDENTIFIED BY 'secret';
#GRANT ALL PRIVILEGES ON *.* TO 'username'@'ip_address' WITH GRANT OPTION;
#CREATE USER 'username'@'%' IDENTIFIED BY 'secret';
#GRANT ALL PRIVILEGES ON *.* TO 'usernemae'@'%' WITH GRANT OPTION;
#FLUSH PRIVILEGES;
##
function allow_remote_client_access() {
    if [[ "${AUTO_INSTALL}" == true ]]; then
        if "${MYSQL_ALLOW_REMOTE}"; then
            ENABLE_REMOTE_ACCESS="y"
        else
            ENABLE_REMOTE_ACCESS="n"
        fi
    else
        while [[ "${ENABLE_REMOTE_ACCESS}" != "y" && "${ENABLE_REMOTE_ACCESS}" != "n" ]]; do
            read -rp "Do you want to allow MySQL remote client access? [y/n]: " -e ENABLE_REMOTE_ACCESS
        done
    fi

    if [[ ${ENABLE_REMOTE_ACCESS} == y* ]]; then
        REMOTE_CLIENT_CNF="###################################
# Custom optimization for LEMPer
# Allow remote client access
#
[mysqld]
skip-networking=0
skip-bind-address"

        if [[ -d /etc/mysql/mariadb.conf.d ]]; then
            run touch /etc/mysql/mariadb.conf.d/20-allow-remote-client-access.cnf
            run bash -c "echo '${REMOTE_CLIENT_CNF}' > /etc/mysql/mariadb.conf.d/20-allow-remote-client-access.cnf"
        else
            run bash -c "echo -e '\n${REMOTE_CLIENT_CNF}' >> /etc/mysql/my.cnf"
        fi
    fi
}

echo "[MariaDB (MySQL drop-in replacement) Installation]"

# Start running things from a call at the end so if this script is executed
# after a partial download it doesn't do anything.
if [[ -n $(command -v mariadb) && -n $(command -v mariadbd) && "${FORCE_INSTALL}" != true ]]; then
    info "MariaDB server already exists, installation skipped."
else
    init_mariadb_install "$@"
fi
