#!/bin/bash

## Exit codes

EXIT_VALIDATION_ERROR=1
EXIT_ERROR=2
EXIT_ALREADY_CONFIGURED=3


# get product name, default: SUSE Manager
IFS=" = "
DEFAULT_RHN_CONF="/usr/share/rhn/config-defaults/rhn.conf"

if [ -f "$DEFAULT_RHN_CONF" ]; then
    while read -r name value
    do
        if [ "$name" == "product_name" ]; then
            PRODUCT_NAME=$value
        fi
    done < $DEFAULT_RHN_CONF
fi
if [ ! -n "$PRODUCT_NAME" ]; then
    PRODUCT_NAME="SUSE Manager"
fi

DISTRIBUTION_ID="$(source /etc/os-release && echo ${ID})"
case ${DISTRIBUTION_ID} in
    sles|suse-manager-server)
        JVM='/usr/lib64/jvm/jre-17-openjdk/bin/java'
        if [ ! -f $JVM ]; then
            JVM='/usr/lib64/jvm/jre-11-openjdk/bin/java'
        fi;;
    opensuse|opensuse-leap)
        JVM='/usr/lib64/jvm/jre-17-openjdk/bin/java'
        if [ ! -f $JVM ]; then
            JVM='/usr/lib64/jvm/jre-11-openjdk/bin/java'
        fi;;
    *)                        echo 'Unknown distribution!'
                              exit $EXIT_VALIDATION_ERROR;;
esac

if [ ! $UID -eq 0 ]; then
    echo "You need to be superuser (root) to run this script!"
    exit $EXIT_VALIDATION_ERROR
fi

# ensure correct java version is being used (bsc#1049575)
echo "Asserting correct java version..."
update-alternatives --set java ${JVM}
if [ ! $? -eq 0 ]; then
    echo "Failed to set ${JVM} as default java version!"
    exit $EXIT_VALIDATION_ERROR
fi

if [[ -n "$TZ" ]]; then
    timedatectl set-timezone $TZ
fi

TMPDIR="/var/spacewalk/tmp"

SETUP_ENV="/root/setup_env.sh"
MANAGER_COMPLETE="/root/.MANAGER_SETUP_COMPLETE"

LOCAL_DB=1
DB_BACKEND="postgresql"

function help() {
    echo "
Usage: $0 [OPTION]
helper script to do migration or setup of $PRODUCT_NAME

  -h             this help screen
"
}

ask_input() {
    # Set using an env variable or to an empty string.
    VARIABLE=$1
    if [ -z ${!VARIABLE+x} ]; then
        declare $VARIABLE=
    fi
}

setup_mail () {
    postconf -e myhostname=$HOSTNAME
    # bsc#979664 - SUSE Manager requires a working mail system
    systemctl --quiet enable postfix 2>&1
    systemctl restart postfix
}

exists_db() {
    PGNAME=$1
    if [ $EXTERNALDB = 0 ]; then
        EXISTS=$(runuser - postgres -c 'psql -t -c "select datname from pg_database where datname='"'$PGNAME'"';"')
    else
        EXISTS=$(echo "select datname from pg_database where datname='$PGNAME';" | (export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -t -U $EXTERNALDB_ADMIN_USER -h $MANAGER_DB_HOST))
    fi
    if [ "x$EXISTS" == "x $PGNAME" ] ; then
        return 0
    else
        return 1
    fi
}

exists_user() {
    if [ $EXTERNALDB = 0 ] ; then
        EXISTS=$($RUNUSER - postgres -c 'psql -t -c "select usename from pg_user where usename='"'$MANAGER_USER'"';"')
    else
        EXISTS=$(echo "select usename from pg_user where usename='$MANAGER_USER';" | (export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -t -U $EXTERNALDB_ADMIN_USER -h $MANAGER_DB_HOST))
    fi
    if [ "x$EXISTS" == "x $MANAGER_USER" ] ; then
        return 0
    else
        return 1
    fi
}

setup_db_postgres() {
    if [ $EXTERNALDB = 0 ]; then
        POSTGRESQLSERVICE=$(systemctl list-unit-files | grep -m 1 postgresql | cut -f1 -d. | tr -d '\n')
        DATADIR=$(runuser -l postgres -c env | grep PGDATA | cut -f2- -d=)
        systemctl --quiet enable ${POSTGRESQLSERVICE} 2>&1
        if [[ "echo $(source /etc/os-release && echo ${ID_LIKE})" != *"suse"* ]]; then
            # Create the PostgreSQL data folder, should it not exist.
            if [ ! -f $DATADIR/PG_VERSION ]; then
                rm -Rf ${DATADIR}
                POSTGRES_LANG=en_US.UTF-8

                # Define LC_CTYPE in postgres user profile. (Used during any DB creation)
                PGHOME=$(getent passwd postgres | awk -F: '{print $6}')
                . $PGHOME/.i18n 2>/dev/null
                if [ -z $LC_CTYPE ]; then
                    grep "^LC_CTYPE" $PGHOME/.i18n > /dev/null 2>&1
                    if [ $? = 0 ]; then
                        sed -i -e "s/^LC_CTYPE.*$/LC_CTYPE=${POSTGRES_LANG}/" $PGHOME/.i18n
                    else
                        echo -e "LC_CTYPE=${POSTGRES_LANG}\nexport LC_CTYPE" >> $PGHOME/.i18n
                    fi
                fi

                echo "Initializing PostgreSQL $VERSION at location ${DATADIR}"
                # Redundant locale flag for clarity
                runuser -l postgres -c "/usr/bin/initdb --locale=${POSTGRES_LANG} --auth=ident $DATADIR" &> initlog || {
                    echo "Initialisation failed. See $PWD/initlog ."
                    exit $EXIT_ERROR
                }
            fi
        else
            # Define POSTGRES_LANG in system wide config. (Used during any DB creation)
            . /etc/sysconfig/postgresql
            if [ -z $POSTGRES_LANG ]; then
                grep "^POSTGRES_LANG" /etc/sysconfig/postgresql > /dev/null 2>&1
                if [ $? = 0 ]; then
                    sed -i -e "s/^POSTGRES_LANG.*$/POSTGRES_LANG=\"en_US.UTF-8\"/" /etc/sysconfig/postgresql
                else
                    echo "POSTGRES_LANG=\"en_US.UTF-8\"" >> /etc/sysconfig/postgresql
                fi
            fi
        fi
        systemctl start ${POSTGRESQLSERVICE}
        if ! exists_db $MANAGER_DB_NAME; then
            # required for postgresql <= 13 before creating the user
            echo "password_encryption = 'scram-sha-256'" >> ${DATADIR}/postgresql.conf
            systemctl restart ${POSTGRESQLSERVICE}
            su - postgres -c "createdb -E UTF8 $MANAGER_DB_NAME ; echo \"CREATE ROLE $MANAGER_USER PASSWORD '$MANAGER_PASS' SUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;\" | psql"

            INT_NET=$(ip -o -4 addr show up scope global | head -1 | awk '{print $4}')
            echo "local $MANAGER_DB_NAME postgres peer
    local $MANAGER_DB_NAME $MANAGER_USER scram-sha-256
    host $MANAGER_DB_NAME $MANAGER_USER 127.0.0.1/32 scram-sha-256
    host $MANAGER_DB_NAME $MANAGER_USER ::1/128 scram-sha-256
    host $MANAGER_DB_NAME $MANAGER_USER $INT_NET scram-sha-256" > /tmp/pg_hba.conf
            cat ${DATADIR}/pg_hba.conf >> /tmp/pg_hba.conf
            mv ${DATADIR}/pg_hba.conf ${DATADIR}/pg_hba.conf.bak
            mv /tmp/pg_hba.conf ${DATADIR}/pg_hba.conf
            chmod 600 ${DATADIR}/pg_hba.conf
            chown postgres:postgres ${DATADIR}/pg_hba.conf
            systemctl restart ${POSTGRESQLSERVICE}
        else
            echo "Database exists. Preparing for resetup. All data will be removed."
        fi
    else
        if ! exists_db $MANAGER_DB_NAME; then
            echo "CREATE DATABASE $MANAGER_DB_NAME ENCODING = UTF8 ;" | ( export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -h $MANAGER_DB_HOST -U $EXTERNALDB_ADMIN_USER)
        fi
        if ! exists_user $MANAGER_USER; then
            if [[ -n $EXTERNALDB_PROVIDER && "${EXTERNALDB_PROVIDER,,}" == "aws" ]] ; then
                echo "CREATE ROLE $MANAGER_USER PASSWORD '$MANAGER_PASS'  NOCREATEDB NOCREATEROLE INHERIT LOGIN;" | ( export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -h $MANAGER_DB_HOST -U $EXTERNALDB_ADMIN_USER)
                echo "GRANT rds_superuser to $MANAGER_USER;" | ( export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -h $MANAGER_DB_HOST -U $EXTERNALDB_ADMIN_USER)
                echo "GRANT create on database $MANAGER_DB_NAME to $MANAGER_USER;" | ( export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -h $MANAGER_DB_HOST -U $EXTERNALDB_ADMIN_USER)
            else
                echo "CREATE ROLE $MANAGER_USER PASSWORD '$MANAGER_PASS' SUPERUSER NOCREATEDB NOCREATEROLE INHERIT LOGIN;" | ( export PGPASSWORD=$EXTERNALDB_ADMIN_PASS; exec psql -h $MANAGER_DB_HOST -U $EXTERNALDB_ADMIN_USER)
            fi
        fi
    fi
}

check_re_install() {
if [ -f $MANAGER_COMPLETE ]; then
    echo "$PRODUCT_NAME is already set up. Exit." >&2
    exit $EXIT_ALREADY_CONFIGURED
fi
}

setup_spacewalk() {
    CERT_COUNTRY=`echo -n $CERT_COUNTRY|tr '[:lower:]' '[:upper:]'`

    [ -d "/etc/pki/trust/anchors" ] && CA_PATH=/etc/pki/trust/anchors || CA_PATH=/etc/pki/ca-trust/source/anchors
    if [ -z "$REPORT_DB_CA_CERT" ]; then
        REPORT_DB_CA_CERT="$CA_PATH/LOCAL-RHN-ORG-TRUSTED-SSL-CERT"
    fi

    echo "admin-email = $MANAGER_ADMIN_EMAIL
ssl-set-org = $CERT_O
ssl-set-org-unit = $CERT_OU
ssl-set-city = $CERT_CITY
ssl-set-state = $CERT_STATE
ssl-set-country = $CERT_COUNTRY
ssl-set-cnames = $CERT_CNAMES
ssl-password = $CERT_PASS
ssl-set-email = $CERT_EMAIL
ssl-config-sslvhost = Y
ssl-ca-cert-expiration = 10
ssl-server-cert-expiration = 10
db-backend=$DB_BACKEND
db-user=$MANAGER_USER
db-password=$MANAGER_PASS
db-name=$MANAGER_DB_NAME
db-host=$MANAGER_DB_HOST
db-port=$MANAGER_DB_PORT
db-protocol=$MANAGER_DB_PROTOCOL
externaldb=$EXTERNALDB
externaldb-admin-user=$EXTERNALDB_ADMIN_USER
externaldb-admin-password=$EXTERNALDB_ADMIN_PASS
db-ca-cert=$MANAGER_DB_CA_CERT
report-db-ca-cert=$REPORT_DB_CA_CERT
externaldb-provider=$EXTERNALDB_PROVIDER
report-db-backend=postgresql
report-db-name=$REPORT_DB_NAME
report-db-host=$REPORT_DB_HOST
report-db-port=$REPORT_DB_PORT
report-db-user=$REPORT_DB_USER
report-db-password=$REPORT_DB_PASS
enable-tftp=$MANAGER_ENABLE_TFTP
product_name=$PRODUCT_NAME
hostname=$HOSTNAME
" > /root/spacewalk-answers

    if [ -n "$SCC_USER" ]; then
        echo "scc-user = $SCC_USER
scc-pass = $SCC_PASS
" >> /root/spacewalk-answers
        PARAM_CC="--scc"
    elif [ -n "$ISS_PARENT" ]; then
        PARAM_CC="--disconnected"
    fi

    if [ "$NO_SSL" == "Y" ]; then
        echo "no-ssl = Y
" >>/root/spacewalk-answers
        PARAM_CC="$PARAM_CC --skip-ssl-cert-generation"

        sed '/ssl/Id' -i /etc/apache2/conf.d/zz-spacewalk-www.conf
        echo "server.no_ssl = 1" >>/etc/rhn/rhn.conf
        sed '/<IfDefine SSL/,/<\/IfDefine SSL/d' -i /etc/apache2/listen.conf
    else
        echo "ssl-use-existing-certs = N" >> /root/spacewalk-answers

        # check if CA Cert and Key exists and try to use it to generate the server certs
        if [ -e /root/ssl-build/RHN-ORG-TRUSTED-SSL-CERT -a -e /root/ssl-build/RHN-ORG-PRIVATE-SSL-KEY ]; then
                PARAM_CC="$PARAM_CC --skip-ssl-ca-generation"
        fi
    fi

    PARAM_DB="--external-postgresql"

    /usr/bin/spacewalk-setup --non-interactive --clear-db $PARAM_CC --answer-file=/root/spacewalk-answers $PARAM_DB
    SWRET=$?
    if [ "x" = "x$MANAGER_MAIL_FROM" ]; then
        MANAGER_MAIL_FROM="$PRODUCT_NAME ($HOSTNAME) <root@$HOSTNAME>"
    fi
    if ! grep "^web.default_mail_from" /etc/rhn/rhn.conf > /dev/null; then
        echo "web.default_mail_from = $MANAGER_MAIL_FROM" >> /etc/rhn/rhn.conf
    fi

    if [ ! -f /srv/susemanager/salt/images/rhn-org-trusted-ssl-cert-osimage-1.0-1.noarch.rpm ]; then
        /usr/sbin/mgr-package-rpm-certificate-osimage
    fi

    # rm /root/spacewalk-answers
    if [ "$SWRET" != "0" ]; then
        echo "ERROR: spacewalk-setup failed" >&2
        exit $EXIT_ERROR
    fi
}

do_setup() {
    if [ -f $SETUP_ENV ]; then
        . $SETUP_ENV
    else
        # ask for the needed values if the setup_env file does not exist
        ask_input MANAGER_USER
        ask_input MANAGER_PASS
        ask_input MANAGER_ADMIN_EMAIL
        ask_input CERT_CNAMES
        ask_input CERT_O
        ask_input CERT_OU
        ask_input CERT_CITY
        ask_input CERT_STATE
        ask_input CERT_COUNTRY
        ask_input CERT_EMAIL
        ask_input CERT_PASS
        ask_input LOCAL_DB
        ask_input DB_BACKEND
        ask_input MANAGER_DB_NAME
        ask_input MANAGER_DB_HOST
        ask_input MANAGER_DB_PORT
        ask_input MANAGER_DB_CA_CERT
        ask_input MANAGER_DB_PROTOCOL
        ask_input MANAGER_ENABLE_TFTP
        ask_input EXTERNALDB_ADMIN_USER
        ask_input EXTERNALDB_ADMIN_PASS
        ask_input EXTERNALDB_PROVIDER
        ask_input SCC_USER
        ask_input SCC_PASS
        ask_input ISS_PARENT
        ask_input ACTIVATE_SLP
        ask_input REPORT_DB_NAME
        ask_input REPORT_DB_HOST
        ask_input REPORT_DB_PORT
        ask_input REPORT_DB_USER
        ask_input REPORT_DB_PASS
        ask_input REPORT_DB_CA_CERT
        ask_input UYUNI_FQDN
    fi;
    if [ -z "$SYS_DB_PASS" ]; then
        SYS_DB_PASS=`dd if=/dev/urandom bs=16 count=4 2> /dev/null | md5sum | cut -b 1-8`
    fi
    if [ -z "$MANAGER_DB_NAME" ]; then
        MANAGER_DB_NAME="susemanager"
    fi
    if [ -z "$DB_BACKEND" ]; then
        DB_BACKEND="postgresql"
    fi
    if [ -z "$REPORT_DB_NAME" ]; then
        REPORT_DB_NAME="reportdb"
    fi
    if [ -z "$REPORT_DB_HOST" ]; then
        REPORT_DB_HOST="localhost"
    fi
    if [ -z "$REPORT_DB_PORT" ]; then
        REPORT_DB_PORT="5432"
    fi
    if [ -z "$REPORT_DB_USER" ]; then
        REPORT_DB_USER="pythia_susemanager"
    fi
    if [ -z "$MANAGER_DB_HOST" ]; then
        MANAGER_DB_HOST="localhost"
    fi

    case $MANAGER_DB_HOST in
        "localhost"|$(hostname -s)|$(hostname -f)|"")
            EXTERNALDB=0 ;;
        *)
            EXTERNALDB=1 ;;
    esac

    if [ -z "$NO_SSL" ]; then
        NO_SSL=
    fi
    if [ -n "$UYUNI_FQDN" ]; then
        HOSTNAME=$UYUNI_FQDN
    fi

    check_re_install
    echo "Do not delete this file unless you know what you are doing!" > $MANAGER_COMPLETE
    setup_mail
    if [ "$DB_BACKEND" = "postgresql" ]; then
        setup_db_postgres
    fi

    setup_spacewalk

    # In the container case, we have the MIRROR_PATH environment variable at setup
    if [ -n "$MIRROR_PATH" ]; then
        echo "server.susemanager.fromdir = $MIRROR_PATH" >> /etc/rhn/rhn.conf
    fi

    if [ -n "$ISS_PARENT" ]; then
        local certname=`echo "MASTER-$ISS_PARENT-TRUSTED-SSL-CERT" | sed 's/\./_/g'`
        curl -s -S -o /usr/share/rhn/$certname "http://$ISS_PARENT/pub/RHN-ORG-TRUSTED-SSL-CERT"
        if [ -e /usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT ] && \
           cmp -s /usr/share/rhn/RHN-ORG-TRUSTED-SSL-CERT /usr/share/rhn/$certname ; then
            # equal - use it
            rm -f /usr/share/rhn/$certname
            certname=RHN-ORG-TRUSTED-SSL-CERT
        else
            /usr/share/rhn/certs/update-ca-cert-trust.sh $certname
        fi
        echo "
        INSERT INTO rhnISSMaster (id, label, is_current_master, ca_cert)
        VALUES (sequence_nextval('rhn_issmaster_seq'), '$ISS_PARENT', 'Y', '/usr/share/rhn/$certname');
        " | spacewalk-sql -
    fi
}

####################################################
# Start
####################################################

PROGRAM="$0"

while [ -n "$1" ]
do
    p="$1"

    case "$p" in
    -h)
        help
       ;;
    -s)
        # Keep until removed from mgradm
       ;;
    -n)
        # Keep until removed from mgradm
        ;;
    *)
       echo
       echo "Option \"$p\" is not recognized. Type \"$PROGRAM -h\" for help."
       echo
       exit $EXIT_VALIDATION_ERROR
       ;;
    esac

    shift
done

do_setup

if [ "$EXTERNALDB" = "0" ]; then
    /usr/sbin/spacewalk-service stop
    /usr/bin/smdba system-check autotuning --max_connections=400

    # Find PostgreSQL service name.
    POSTGRESQLSERVICE=$(systemctl list-unit-files | grep -m 1 postgresql | cut -f1 -d. | tr -d '\n')
    systemctl restart $POSTGRESQLSERVICE
fi
/usr/sbin/spacewalk-service start
systemctl --quiet enable spacewalk-diskcheck.timer 2>&1
systemctl start spacewalk-diskcheck.timer

# vim: set expandtab:
