Keep previous installation intact, build before switching the symlink, improve error handling and add service and issuer checks.
948 lines
25 KiB
Bash
Executable File
948 lines
25 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
script_name="$(basename $(realpath $0))"
|
|
working_dir="$(dirname $(realpath $0))"
|
|
|
|
#conf_file="${working_dir}/conf/${script_name%%.*}.conf"
|
|
conf_file="${working_dir}/conf/keycloak.conf"
|
|
|
|
LOCK_DIR="/tmp/$(basename $0).$$.LOCK"
|
|
log_file="${LOCK_DIR}/${script_name%%.*}.log"
|
|
|
|
backup_date="$(date +%Y-%m-%d-%H%M)"
|
|
|
|
keycloak_service_was_active=false
|
|
symlink_switched=false
|
|
|
|
# ----------
|
|
# Base Function(s)
|
|
# ----------
|
|
|
|
clean_up() {
|
|
|
|
# Perform program exit housekeeping
|
|
rm -rf "$LOCK_DIR"
|
|
blank_line
|
|
exit $1
|
|
}
|
|
|
|
echononl(){
|
|
if $terminal ; then
|
|
echo X\\c > /tmp/shprompt$$
|
|
if [ `wc -c /tmp/shprompt$$ | awk '{print $1}'` -eq 1 ]; then
|
|
echo -e -n " $*\\c" 1>&2
|
|
else
|
|
echo -e -n " $*" 1>&2
|
|
fi
|
|
rm /tmp/shprompt$$
|
|
fi
|
|
}
|
|
|
|
fatal(){
|
|
if $terminal ; then
|
|
echo ""
|
|
echo -e " [ \033[31m\033[1mFatal\033[m ] $*"
|
|
echo ""
|
|
echo -e " \033[1mScript is canceled\033[m.."
|
|
echo ""
|
|
else
|
|
echo ""
|
|
echo -e " [ Fatal ] $*"
|
|
echo ""
|
|
echo -e " Script is canceled.."
|
|
echo ""
|
|
fi
|
|
if ${keycloak_service_was_active:-false} && ! ${symlink_switched:-false} && \
|
|
! systemctl is-active --quiet keycloak.service ; then
|
|
echononl "Restart previous Keycloak installation.."
|
|
if systemctl start keycloak.service > /dev/null 2>&1 ; then
|
|
echo_ok
|
|
else
|
|
echo_failed
|
|
error "The previous Keycloak service could not be restarted automatically."
|
|
fi
|
|
fi
|
|
|
|
rm -rf "$LOCK_DIR"
|
|
exit 1
|
|
}
|
|
|
|
error (){
|
|
echo ""
|
|
if $terminal ; then
|
|
echo -e " [ \033[31m\033[1mError\033[m ] $*"
|
|
else
|
|
echo " [ Error ] $*"
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
warn (){
|
|
echo ""
|
|
if $terminal ; then
|
|
echo -e " [ \033[33m\033[1mWarning\033[m ] $*"
|
|
else
|
|
echo " [ Error ] $*"
|
|
fi
|
|
echo ""
|
|
}
|
|
|
|
info (){
|
|
if $terminal ; then
|
|
echo ""
|
|
if $terminal ; then
|
|
echo -e " [ \033[32m\033[1mInfo\033[m ] $*"
|
|
else
|
|
echo " [ Info ] $*"
|
|
fi
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
|
|
echo_ok() {
|
|
if $terminal ; then
|
|
echo -e "\033[85G[ \033[32mok\033[m ]"
|
|
fi
|
|
}
|
|
echo_failed(){
|
|
if $terminal ; then
|
|
echo -e "\033[85G[ \033[1;31mfailed\033[m ]"
|
|
fi
|
|
}
|
|
echo_skipped() {
|
|
if $terminal ; then
|
|
echo -e "\033[85G[ \033[33m\033[1mskipped\033[m ]"
|
|
fi
|
|
}
|
|
echo_wait(){
|
|
if $terminal ; then
|
|
echo -en "\033[85G[ \033[5m\033[1m..\033[m ]"
|
|
fi
|
|
}
|
|
|
|
trim() {
|
|
local var="$*"
|
|
var="${var#"${var%%[![:space:]]*}"}" # remove leading whitespace characters
|
|
var="${var%"${var##*[![:space:]]}"}" # remove trailing whitespace characters
|
|
echo -n "$var"
|
|
}
|
|
|
|
blank_line() {
|
|
if $terminal ; then
|
|
echo ""
|
|
fi
|
|
}
|
|
|
|
detect_os () {
|
|
|
|
if $(which lsb_release > /dev/null 2>&1) ; then
|
|
|
|
DIST="$(lsb_release -i | awk '{print tolower($3)}')"
|
|
DIST_VERSION="$(lsb_release -r | awk '{print tolower($2)}')"
|
|
DIST_CODENAME="$(lsb_release -c | awk '{print tolower($2)}')"
|
|
|
|
if [[ "$DIST" = "debian" ]]; then
|
|
if $(echo "$DIST_VERSION" | grep -q '\.') ; then
|
|
DIST_VERSION=$(echo "$DIST_VERSION" | cut --delimiter='.' -f1)
|
|
fi
|
|
fi
|
|
|
|
elif [[ -e "/etc/os-release" ]]; then
|
|
|
|
. /etc/os-release
|
|
|
|
DIST=$ID
|
|
DIST_VERSION=${VERSION_ID}
|
|
|
|
fi
|
|
|
|
# remove whitespace from DIST and DIST_VERSION
|
|
DIST="${DIST// /}"
|
|
DIST_VERSION="${DIST_VERSION// /}"
|
|
|
|
}
|
|
|
|
# Funktion zur Generierung eines zufälligen Zeichens aus einer gegebenen Zeichenmenge
|
|
random_char() {
|
|
local chars="$1"
|
|
echo -n "${chars:RANDOM%${#chars}:1}"
|
|
}
|
|
|
|
# Funktion zur Generierung eines zufälligen Strings mit den angegebenen Anforderungen
|
|
generate_random_string() {
|
|
local length="$1"
|
|
|
|
# Überprüfen, ob die Länge größer als 8 ist
|
|
if [[ "$length" -le 8 ]]; then
|
|
echo "Fehler: Die Länge muss größer als 8 Zeichen sein."
|
|
return 1
|
|
fi
|
|
|
|
# Zeichenmengen
|
|
local lower="abcdefghijklmnopqrstuvwxyz"
|
|
local upper="ABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
|
local digits="0123456789"
|
|
#local special="!@#$%^&*()_+-=[]{}|;:,.<>?/"
|
|
local special="_+--//...."
|
|
|
|
# Generiere mindestens ein Zeichen aus jeder Kategorie
|
|
local random_string=$(random_char "$lower")
|
|
random_string+=$(random_char "$upper")
|
|
random_string+=$(random_char "$digits")
|
|
random_string+=$(random_char "$special")
|
|
random_string+=$(random_char "$special")
|
|
|
|
# Fülle den Rest der Zeichenkette mit zufälligen Zeichen aus allen Kategorien
|
|
local all_chars="$lower$upper$digits$special"
|
|
for (( i=${#random_string}; i<length; i++ )); do
|
|
random_string+=$(random_char "$all_chars")
|
|
done
|
|
|
|
# Mische die Zeichenkette, um die Reihenfolge der Zeichen zufällig zu machen
|
|
random_string=$(echo "$random_string" | fold -w1 | shuf | tr -d '\n')
|
|
|
|
# Ausgabe des generierten Strings
|
|
echo "$random_string"
|
|
}
|
|
|
|
|
|
|
|
# ----------
|
|
# - Jobhandling
|
|
# ----------
|
|
|
|
# - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM
|
|
# -
|
|
trap 'fatal "Interrupted by signal."' SIGHUP SIGINT SIGTERM
|
|
|
|
# - Create lock directory '$LOCK_DIR"
|
|
#
|
|
mkdir "$LOCK_DIR"
|
|
|
|
|
|
# ----------
|
|
# - Some checks ..
|
|
# ----------
|
|
|
|
# - Running in a terminal?
|
|
# -
|
|
if [[ -t 1 ]] ; then
|
|
terminal=true
|
|
else
|
|
fatal "Script must run in a terminal."
|
|
fi
|
|
|
|
|
|
# ==========
|
|
# - Begin Main Script
|
|
# ==========
|
|
|
|
# ----------
|
|
# - Headline
|
|
# ----------
|
|
|
|
if $terminal ; then
|
|
echo ""
|
|
echo -e "\033[1m----------\033[m"
|
|
echo -e "\033[32m\033[1mRunning script \033[m\033[1m$script_name\033[32m .. \033[m"
|
|
echo -e "\033[1m----------\033[m"
|
|
fi
|
|
|
|
|
|
# ----------
|
|
# Read Configurations from $conf_file
|
|
# ----------
|
|
|
|
# - Give your default values here
|
|
# -
|
|
DEFAULT_FQHN_HOSTNAME="$(hostname -f)"
|
|
|
|
DEFAULT_KEYCLOAK_USER="keycloak"
|
|
|
|
DEFAULT_DB_NAME="keycloak"
|
|
DEFAULT_DB_USER="keycloak"
|
|
|
|
DEFAULT_KEYCLOAK_BASE_INSTALL_PATH="/opt"
|
|
|
|
blank_line
|
|
echononl "Read configuration '$(basename "${conf_file}")' .."
|
|
if [[ -f "$conf_file" ]]; then
|
|
source "$conf_file" > ${log_file} 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
error "$(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
else
|
|
echo_skipped
|
|
warn "No configuration file '$conf_file' present.\n
|
|
Loading default values.."
|
|
fi
|
|
|
|
[[ -n "${FQHN_HOSTNAME}" ]] && DEFAULT_FQHN_HOSTNAME="${FQHN_HOSTNAME}"
|
|
|
|
if [[ -n "$DB_TYPE" ]] ; then
|
|
if [[ "${DB_TYPE,,}" = "postgres" ]] || [[ "${DB_TYPE,,}" = "postgresql" ]] || [[ "${DB_TYPE,,}" = "pgsql" ]] || [[ "${DB_TYPE,,}" = "psql" ]] ; then
|
|
|
|
DEFAULT_DB_TYPE=pgsql
|
|
|
|
elif [[ "${DB_TYPE,,}" = "mysql" ]] ; then
|
|
|
|
DEFAULT_DB_TYPE=mysql
|
|
|
|
else
|
|
DEFAULT_DB_TYPE=pgsql
|
|
#fatal "Wrong or empty Database Type (DB_TYPE) - must be 'mysql' or 'pgsql'."
|
|
fi
|
|
fi
|
|
|
|
[[ -n "${DB_NAME}" ]] && DEFAULT_DB_NAME="${DB_NAME}"
|
|
[[ -n "${DB_USER}" ]] && DEFAULT_DB_USER="${DB_USER}"
|
|
|
|
#if [[ -n "${DB_PASS}" ]] ; then
|
|
# DEFAULT_DB_PASS="${DB_PASS}"
|
|
#else
|
|
# fatal "No Password given for ${DB_TYPE} database ${DEFAULT_DB_NAME}"
|
|
#fi
|
|
|
|
if [[ -n "${DB_PASS}" ]] ; then
|
|
DEFAULT_DB_PASS="${DB_PASS}"
|
|
else
|
|
DEFAULT_DB_PASS=""
|
|
fi
|
|
|
|
|
|
[[ -n "${KEYCLOAK_USER}" ]] && DEFAULT_KEYCLOAK_USER="${KEYCLOAK_USER}"
|
|
if [[ -n "${KEYCLOAK_GROUP}" ]]; then
|
|
DEFAULT_KEYCLOAK_GROUP="${KEYCLOAK_GROUP}"
|
|
else
|
|
DEFAULT_KEYCLOAK_GROUP="$DEFAULT_KEYCLOAK_USER"
|
|
fi
|
|
|
|
[[ -n "${KEYCLOAK_BASE_INSTALL_PATH}" ]] && DEFAULT_KEYCLOAK_BASE_INSTALL_PATH="${KEYCLOAK_BASE_INSTALL_PATH}"
|
|
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Version Number of Keycloak Server to install"
|
|
echo ""
|
|
echo " see: https://keycloak.org/downloads"
|
|
echo ""
|
|
echo ""
|
|
KEYCLOAK_VERSION=
|
|
while [ "X$KEYCLOAK_VERSION" = "X" ]
|
|
do
|
|
echononl "KEYCLOAK Server Version: "
|
|
read KEYCLOAK_VERSION
|
|
if [ "X$KEYCLOAK_VERSION" = "X" ]; then
|
|
echo -e "\n\t\033[33m\033[1mA Version number is required!\033[m\n"
|
|
fi
|
|
done
|
|
if [[ ! "${KEYCLOAK_VERSION}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then
|
|
fatal "Invalid Keycloak version '${KEYCLOAK_VERSION}'. Expected format: 26.7.3"
|
|
fi
|
|
DOWNLOAD_ARCHIVE="keycloak-${KEYCLOAK_VERSION}.tar.gz"
|
|
DOWNLOAD_URL="https://github.com/keycloak/keycloak/releases/download/${KEYCLOAK_VERSION}/${DOWNLOAD_ARCHIVE}"
|
|
|
|
|
|
KEYCLOAK_BASE_INSTALL_PATH=
|
|
echo ""
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Specify the base directory in which keycloak is to be installed."
|
|
echo ""
|
|
while [[ "X${KEYCLOAK_BASE_INSTALL_PATH}" = "X" ]]; do
|
|
echononl "Base directory for keycloak installation [${DEFAULT_KEYCLOAK_BASE_INSTALL_PATH}]: "
|
|
read KEYCLOAK_BASE_INSTALL_PATH
|
|
if [[ "X${KEYCLOAK_BASE_INSTALL_PATH}" = "X" ]]; then
|
|
KEYCLOAK_BASE_INSTALL_PATH="${DEFAULT_KEYCLOAK_BASE_INSTALL_PATH}"
|
|
fi
|
|
if [[ ! -d "${KEYCLOAK_BASE_INSTALL_PATH}" ]] ; then
|
|
echo -e "\n\tGiven directory \033[33m\033[1m${KEYCLOAK_BASE_INSTALL_PATH}\033[m does not exist!.\n"
|
|
KEYCLOAK_BASE_INSTALL_PATH=""
|
|
fi
|
|
done
|
|
KEYCLOAK_INSTALL_DIR="${KEYCLOAK_BASE_INSTALL_PATH}/keycloak-${KEYCLOAK_VERSION}"
|
|
|
|
if [[ -h "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak" ]] ; then
|
|
CUR_INSTALL_DIR="$(realpath "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak")"
|
|
CUR_VERSION="$(basename "${CUR_INSTALL_DIR}" | sed "s/^keycloak-//")"
|
|
else
|
|
fatal "Cannot find a Keycloak installation in the ${KEYCLOAK_BASE_INSTALL_PATH} directory"
|
|
fi
|
|
|
|
KEYCLOAK_USER="$(stat -c '%U' "${CUR_INSTALL_DIR}")"
|
|
if [[ -z "${KEYCLOAK_USER}" ]] ; then
|
|
fatal "Cannot determine the user of the Keycloak installation."
|
|
fi
|
|
|
|
KEYCLOAK_GROUP="$(stat -c '%G' "${CUR_INSTALL_DIR}")"
|
|
if [[ -z "${KEYCLOAK_GROUP}" ]] ; then
|
|
fatal "Cannot determine the group of the Keycloak installation."
|
|
fi
|
|
|
|
|
|
FQHN_HOSTNAME=
|
|
echo ""
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Insert full qualified hostname for Keycloak Service"
|
|
echo ""
|
|
if [[ -n "${DEFAULT_FQHN_HOSTNAME}" ]]; then
|
|
while [[ "X${FQHN_HOSTNAME}" = "X" ]]; do
|
|
echononl "Full qualified hostname [${DEFAULT_FQHN_HOSTNAME}]: "
|
|
read FQHN_HOSTNAME
|
|
if [[ "X${FQHN_HOSTNAME}" = "X" ]]; then
|
|
FQHN_HOSTNAME=$DEFAULT_FQHN_HOSTNAME
|
|
fi
|
|
if [[ ! ${FQHN_HOSTNAME} =~ \. ]]; then
|
|
echo -e "\n\tGiven Host \033[33m\033[1m${FQHN_HOSTNAME}\033[m seems not to be a full qualified hostname.\n"
|
|
FQHN_HOSTNAME=""
|
|
fi
|
|
done
|
|
else
|
|
while [[ "X${FQHN_HOSTNAME}" = "X" ]]; do
|
|
echononl "Full qualified hostname: "
|
|
read FQHN_HOSTNAME
|
|
if [[ "X${FQHN_HOSTNAME}" = "X" ]]; then
|
|
echo -e "\n\t\033[33m\033[1mFull qualified hostname is reqired\033[m\n"
|
|
fi
|
|
if [[ ! ${FQHN_HOSTNAME} =~ \. ]]; then
|
|
echo -e "\n\tGiven Host \033[33m\033[1m${FQHN_HOSTNAME}\033[m seems not to be a full qualified hostname.\n"
|
|
FQHN_HOSTNAME=""
|
|
fi
|
|
done
|
|
fi
|
|
HOSTNAME="${FQHN_HOSTNAME%%.*}"
|
|
|
|
|
|
DB_TYPE=
|
|
echo ""
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Specify the database type for the Keycloak database."
|
|
echo ""
|
|
echo " Accepted values: pgsql, postgresql, postgres (for PostgreSQL)"
|
|
echo " mysql (for MySQL)"
|
|
echo ""
|
|
while [[ "X${DB_TYPE}" = "X" ]]; do
|
|
echononl "Database type [${DEFAULT_DB_TYPE}]: "
|
|
read DB_TYPE
|
|
if [[ "X${DB_TYPE}" = "X" ]]; then
|
|
DB_TYPE="${DEFAULT_DB_TYPE}"
|
|
fi
|
|
if [[ "${DB_TYPE,,}" = "postgres" ]] || [[ "${DB_TYPE,,}" = "postgresql" ]] || [[ "${DB_TYPE,,}" = "pgsql" ]] || [[ "${DB_TYPE,,}" = "psql" ]] ; then
|
|
DB_TYPE=pgsql
|
|
elif [[ "${DB_TYPE,,}" = "mysql" ]] ; then
|
|
DB_TYPE=mysql
|
|
else
|
|
echo -e "\n\t\033[33m\033[1mInvalid database type '${DB_TYPE}'! Use 'pgsql' or 'mysql'.\033[m\n"
|
|
DB_TYPE=""
|
|
fi
|
|
done
|
|
|
|
|
|
DB_NAME=
|
|
echo ""
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Specify the database name for the Keycloak database."
|
|
echo ""
|
|
while [[ "X${DB_NAME}" = "X" ]]; do
|
|
echononl "Database name [${DEFAULT_DB_NAME}]: "
|
|
read DB_NAME
|
|
if [[ "X${DB_NAME}" = "X" ]]; then
|
|
DB_NAME="${DEFAULT_DB_NAME}"
|
|
fi
|
|
done
|
|
|
|
DB_USER=
|
|
echo ""
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Specify the database user for the Keycloak database."
|
|
echo ""
|
|
while [[ "X${DB_USER}" = "X" ]]; do
|
|
echononl "Database user [${DEFAULT_DB_USER}]: "
|
|
read DB_USER
|
|
if [[ "X${DB_USER}" = "X" ]]; then
|
|
DB_USER="${DEFAULT_DB_USER}"
|
|
fi
|
|
done
|
|
|
|
DB_PASS=
|
|
echo ""
|
|
echo -e "\033[32m--\033[m"
|
|
echo ""
|
|
echo "Specify the database password for the Keycloak database."
|
|
echo ""
|
|
while [[ "X${DB_PASS}" = "X" ]]; do
|
|
echononl "Database password"
|
|
if [[ -n "${DEFAULT_DB_PASS}" ]]; then
|
|
echo -n " [current value from config]: ****************"
|
|
else
|
|
echo -n ": "
|
|
fi
|
|
read -s DB_PASS
|
|
echo ""
|
|
if [[ "X${DB_PASS}" = "X" ]]; then
|
|
if [[ -n "${DEFAULT_DB_PASS}" ]]; then
|
|
DB_PASS="${DEFAULT_DB_PASS}"
|
|
else
|
|
echo -e "\n\t\033[33m\033[1mA database password is required!\033[m\n"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
#DB_BACKUP_DIR="${working_dir}/backups"
|
|
DB_BACKUP_DIR="$(dirname "${KEYCLOAK_INSTALL_DIR}")"
|
|
DB_DUMP_FILE="${DB_BACKUP_DIR}/keycloak_db_${backup_date}.sql.gz"
|
|
|
|
|
|
echo ""
|
|
echo ""
|
|
echo -e "\t\033[32mStart upgrade script for Keycloak Service with the following parameters\033[m"
|
|
echo ""
|
|
echo -e "\t(New) Keycloak Server Version...: \033[33m\033[1m${KEYCLOAK_VERSION}\033[m"
|
|
echo ""
|
|
if [[ -n "${CUR_VERSION}" ]] ; then
|
|
echo -e "\tCurrent (old) Keycloak Version..: ${CUR_VERSION}"
|
|
else
|
|
echo -e "\tCurrent (old) Keycloak Version..: \033[33mkeycloak is currently NOT installed\033[m"
|
|
fi
|
|
echo ""
|
|
echo -e "\tFull qualified Hostname.........: ${FQHN_HOSTNAME}"
|
|
echo -e "\tHostname........................: ${HOSTNAME}"
|
|
echo ""
|
|
echo -e "\tKeycloak user...................: ${KEYCLOAK_USER}"
|
|
echo -e "\tKeycloak group..................: ${KEYCLOAK_GROUP}"
|
|
echo ""
|
|
echo -e "\tKeycloak database type..........: ${DB_TYPE}"
|
|
echo -e "\tKeycloak database name..........: ${DB_NAME}"
|
|
echo -e "\tKeycloak database user..........: ${DB_USER}"
|
|
echo -e "\tKeycloak database password......: ********"
|
|
echo ""
|
|
echo -e "\tdatabase dump file..............: ${DB_DUMP_FILE}"
|
|
echo ""
|
|
echo -e "\tKeycloak base install dir.......: ${KEYCLOAK_BASE_INSTALL_PATH}"
|
|
echo -e "\tKeycloak install dir............: ${KEYCLOAK_INSTALL_DIR}"
|
|
echo ""
|
|
echo -e "\tDownload archive................: ${DOWNLOAD_ARCHIVE}"
|
|
echo -e "\tDownload URL....................: ${DOWNLOAD_URL}"
|
|
echo ""
|
|
echo ""
|
|
echononl "einverstanden (yes/no): "
|
|
read OK
|
|
OK=${OK,,}
|
|
while [ "X$OK" != "Xyes" -a "X$OK" != "Xno" ]; do
|
|
echononl "Wrong entry! [yes/no]: "
|
|
read OK
|
|
OK=${OK,,}
|
|
done
|
|
[ $OK = "yes" ] || fatal Repeat with other settings..
|
|
|
|
|
|
echo
|
|
echo -e "\033[37m\033[1mAdjust configuration file..\033[m"
|
|
echo
|
|
|
|
_var="KEYCLOAK_USER"
|
|
_val="${KEYCLOAK_USER}"
|
|
echononl "Update '${_var}' configuration file .."
|
|
if ! $(grep -q -E "^\s*${_var}=\"${_val}\"" "${conf_file}" 2> /dev/null) ; then
|
|
perl -i -n -p -e "s/^\s*${_var}=.*/${_var}=\"${_val}\"/" ${conf_file} > "$log_file" 2>&1
|
|
if [[ "$?" = "0" ]]; then
|
|
echo_ok
|
|
else
|
|
echo_failed
|
|
error "$(cat $log_file)"
|
|
fi
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
|
|
_var="KEYCLOAK_GROUP"
|
|
_val="${KEYCLOAK_GROUP}"
|
|
echononl "Update '${_var}' configuration file .."
|
|
if ! $(grep -q -E "^\s*${_var}=\"${_val}\"" "${conf_file}" 2> /dev/null) ; then
|
|
perl -i -n -p -e "s/^\s*${_var}=.*/${_var}=\"${_val}\"/" ${conf_file} > "$log_file" 2>&1
|
|
if [[ "$?" = "0" ]]; then
|
|
echo_ok
|
|
else
|
|
echo_failed
|
|
error "$(cat $log_file)"
|
|
fi
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
_var="FQHN_HOSTNAME"
|
|
_val="${FQHN_HOSTNAME}"
|
|
echononl "Update '${_var}' configuration file .."
|
|
if ! $(grep -q -E "^\s*${_var}=\"${_val}\"" "${conf_file}" 2> /dev/null) ; then
|
|
perl -i -n -p -e "s/^\s*${_var}=.*/${_var}=\"${_val}\"/" ${conf_file} > "$log_file" 2>&1
|
|
if [[ "$?" = "0" ]]; then
|
|
echo_ok
|
|
else
|
|
echo_failed
|
|
error "$(cat $log_file)"
|
|
fi
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
_var="KEYCLOAK_BASE_INSTALL_PATH"
|
|
_val="${KEYCLOAK_BASE_INSTALL_PATH}"
|
|
echononl "Update '${_var}' configuration file .."
|
|
if ! $(grep -q -E "^\s*${_var}=\"${_val}\"" "${conf_file}" 2> /dev/null) ; then
|
|
perl -i -n -p -e "s#^\s*${_var}=.*#${_var}=\"${_val}\"#" ${conf_file} > "$log_file" 2>&1
|
|
if [[ "$?" = "0" ]]; then
|
|
echo_ok
|
|
else
|
|
echo_failed
|
|
error "$(cat $log_file)"
|
|
fi
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
blank_line
|
|
|
|
#echononl "Continue upgrade (yes/no): "
|
|
#read OK
|
|
#OK=${OK,,}
|
|
#while [ "X$OK" != "Xyes" -a "X$OK" != "Xno" ]; do
|
|
# echononl "Wrong entry! [yes/no]: "
|
|
# read OK
|
|
# OK=${OK,,}
|
|
#done
|
|
#[ $OK = "yes" ] || fatal Repeat with other settings..
|
|
|
|
|
|
echo
|
|
echo -e "\033[37m\033[1mSome pre-installation stuff..\033[m"
|
|
echo
|
|
|
|
echononl "Stop Keycloak Service.."
|
|
if systemctl is-active --quiet keycloak.service ; then
|
|
keycloak_service_was_active=true
|
|
systemctl stop keycloak.service > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "$(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
blank_line
|
|
|
|
|
|
echo
|
|
echo -e "\033[37m\033[1mBackup PostgreSQL database before upgrade..\033[m"
|
|
echo
|
|
|
|
echononl "Create backup directory '${DB_BACKUP_DIR}' .."
|
|
mkdir -p "${DB_BACKUP_DIR}" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
error "$(cat "$log_file")"
|
|
fatal "Cannot create backup directory '${DB_BACKUP_DIR}'"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
|
|
if [[ "${DB_TYPE}" = "pgsql" ]] ; then
|
|
|
|
echononl "Dump PostgreSQL database '${DB_NAME}' to '$(basename "${DB_DUMP_FILE}")' .."
|
|
PGPASSWORD="${DB_PASS}" pg_dump \
|
|
-h localhost \
|
|
-p 5432 \
|
|
-U "${DB_USER}" \
|
|
-d "${DB_NAME}" \
|
|
--format=plain \
|
|
--no-password \
|
|
2> "$log_file" \
|
|
| gzip > "${DB_DUMP_FILE}"
|
|
if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]]; then
|
|
echo_failed
|
|
error "$(cat "$log_file")"
|
|
fatal "PostgreSQL backup failed! Aborting upgrade."
|
|
else
|
|
echo_ok
|
|
info "Database backup: ${DB_DUMP_FILE} ($(du -sh "${DB_DUMP_FILE}" | cut -f1))"
|
|
fi
|
|
|
|
elif [[ "${DB_TYPE}" = "mysql" ]] ; then
|
|
|
|
echononl "Dump MySQL database '${DB_NAME}' to '$(basename "${DB_DUMP_FILE}")' .."
|
|
mysqldump \
|
|
--host=localhost \
|
|
--user="${DB_USER}" \
|
|
--password="${DB_PASS}" \
|
|
--single-transaction \
|
|
--routines \
|
|
--triggers \
|
|
"${DB_NAME}" \
|
|
2> "$log_file" \
|
|
| gzip > "${DB_DUMP_FILE}"
|
|
if [[ ${PIPESTATUS[0]} -ne 0 || ${PIPESTATUS[1]} -ne 0 ]]; then
|
|
echo_failed
|
|
error "$(cat "$log_file")"
|
|
fatal "MySQL backup failed! Aborting upgrade."
|
|
else
|
|
echo_ok
|
|
info "Database backup: ${DB_DUMP_FILE} ($(du -sh "${DB_DUMP_FILE}" | cut -f1))"
|
|
fi
|
|
|
|
fi
|
|
|
|
blank_line
|
|
|
|
|
|
echo
|
|
echo -e "\033[37m\033[1mInstalling Keycloak Service..\033[m"
|
|
echo
|
|
|
|
echononl "Download the latest version (${KEYCLOAK_VERSION}) of the Keycloak Server.."
|
|
if [[ ! -f "${working_dir}/${DOWNLOAD_ARCHIVE}" ]]; then
|
|
wget -O "${working_dir}/${DOWNLOAD_ARCHIVE}" "${DOWNLOAD_URL}" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Download failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
|
|
blank_line
|
|
|
|
if [[ -e "${KEYCLOAK_INSTALL_DIR}" ]]; then
|
|
fatal "Target directory '${KEYCLOAK_INSTALL_DIR}' already exists. Remove or rename it manually after checking its contents."
|
|
fi
|
|
|
|
echononl "Extract the Keycloak Service files.."
|
|
tar -C "${KEYCLOAK_BASE_INSTALL_PATH}" -xvzf "${working_dir}/${DOWNLOAD_ARCHIVE}" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Extracting the Keycloak archive failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
|
|
blank_line
|
|
|
|
echononl "Copy new keycloak.conf to keycloak.conf.ORIG"
|
|
if [[ -f "${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf" ]] ; then
|
|
cp -a "${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf" \
|
|
"${KEYCLOAK_INSTALL_DIR}/conf/keycloak.conf.ORIG" > "$log_file" 2>&1
|
|
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Saving the original keycloak.conf failed: $(cat "$log_file")"
|
|
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
else
|
|
echo_skipped
|
|
fi
|
|
|
|
|
|
echononl "Copy configuration files from the previous installation to the new installation."
|
|
|
|
_failed=false
|
|
: > "$log_file"
|
|
|
|
|
|
SRC_DIR="${CUR_INSTALL_DIR}/conf"
|
|
DST_DIR="${KEYCLOAK_INSTALL_DIR}/conf"
|
|
|
|
for ext in conf json; do
|
|
|
|
# Prüfen ob überhaupt Dateien mit dieser Endung existieren
|
|
shopt -s nullglob
|
|
files=("${SRC_DIR}"/*.${ext})
|
|
shopt -u nullglob
|
|
|
|
if [[ ${#files[@]} -eq 0 ]]; then
|
|
|
|
# no files *.${ext} found in ${SRC_DIR}
|
|
continue
|
|
fi
|
|
|
|
for src_file in "${files[@]}"; do
|
|
filename=$(basename "${src_file}")
|
|
dst_file="${DST_DIR}/${filename}"
|
|
|
|
# Existierende Zieldatei sichern
|
|
if [[ -f "${dst_file}" ]]; then
|
|
|
|
orig_file="${dst_file}.ORIG"
|
|
|
|
# Backup '${dst_file}'
|
|
# '${dst_file}' -> '${orig_file}'
|
|
cp -p "${dst_file}" "${orig_file}" || {
|
|
|
|
echo "Unable to save '$(basename "${dst_file}")'. The file was not copied to the installation directory." >> "$log_file"
|
|
_failed=true
|
|
|
|
# '${dst_file}' nicht sichern. Überspringe.
|
|
continue
|
|
}
|
|
fi
|
|
|
|
# Datei ins Zielverzeichnis kopieren
|
|
# '${src_file}' -> '${dst_file}'"
|
|
cp -p "${src_file}" "${dst_file}" || {
|
|
echo " Copying existing '$(basename "${src_file}")' into to installation directory failed!" >> "$log_file"
|
|
_failed=true
|
|
}
|
|
done
|
|
done
|
|
|
|
if ${_failed} ; then
|
|
echo_failed
|
|
fatal "Copying configuration files failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
|
|
echononl "Copy 'providers/ directory from the previous installation to the new installation."
|
|
cp -a "${CUR_INSTALL_DIR}/providers/." "${KEYCLOAK_INSTALL_DIR}/providers/" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Copying providers failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
echononl "Copy 'themes/ directory from the previous installation to the new installation."
|
|
cp -a "${CUR_INSTALL_DIR}/themes/." "${KEYCLOAK_INSTALL_DIR}/themes/" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Copying themes failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
|
|
echononl "Set ownbership of installation directory '${KEYCLOAK_INSTALL_DIR}'.."
|
|
chown -R ${KEYCLOAK_USER}:${KEYCLOAK_GROUP} "${KEYCLOAK_INSTALL_DIR}" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Setting ownership failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
echononl "Give write permissions to the keycloak group.."
|
|
chmod -R g+w "${KEYCLOAK_INSTALL_DIR}" > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Setting group permissions failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
blank_line
|
|
|
|
echononl "Creates a new and optimized server image.."
|
|
"${KEYCLOAK_INSTALL_DIR}/bin/kc.sh" build > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Creating the optimized server image failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
echononl "Write the effective configuration of the new installation.."
|
|
"${KEYCLOAK_INSTALL_DIR}/bin/kc.sh" show-config > "${working_dir}/current-configuration.txt" 2> "$log_file"
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Reading the effective configuration failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
blank_line
|
|
|
|
echononl "Atomically switch symlink keycloak -> keycloak-${KEYCLOAK_VERSION} .."
|
|
NEW_SYMLINK="${KEYCLOAK_BASE_INSTALL_PATH}/.keycloak.new.$$"
|
|
if ! ln -s "keycloak-${KEYCLOAK_VERSION}" "${NEW_SYMLINK}" > "$log_file" 2>&1 || \
|
|
! mv -Tf "${NEW_SYMLINK}" "${KEYCLOAK_BASE_INSTALL_PATH}/keycloak" >> "$log_file" 2>&1 ; then
|
|
rm -f "${NEW_SYMLINK}"
|
|
echo_failed
|
|
fatal "Switching the Keycloak symlink failed: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
symlink_switched=true
|
|
fi
|
|
|
|
echononl "Start Keycloak Service"
|
|
systemctl start keycloak.service > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
fatal "Starting Keycloak failed. The symlink points to the new version; the old installation remains at '${CUR_INSTALL_DIR}'. Database rollback may be required before starting the old version. Details: $(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
echononl "Restart NGINX Service.."
|
|
systemctl restart nginx > "$log_file" 2>&1
|
|
if [[ $? -ne 0 ]]; then
|
|
echo_failed
|
|
error "$(cat "$log_file")"
|
|
else
|
|
echo_ok
|
|
fi
|
|
|
|
|
|
echo
|
|
echo -e "\033[37m\033[1mSome post-installation stuff..\033[m"
|
|
echo
|
|
|
|
echononl "Wait until the Keycloak service has started completely."
|
|
echo_wait
|
|
declare -i index=0
|
|
declare -i _max_secs_waiting=60
|
|
keycloak_service_started=false
|
|
while true ; do
|
|
|
|
# Try to establish a connection to localhost:8080
|
|
#
|
|
if systemctl is-active --quiet keycloak.service && \
|
|
curl --fail --silent --show-error \
|
|
-H "Host: ${FQHN_HOSTNAME}" \
|
|
-H "X-Forwarded-Host: ${FQHN_HOSTNAME}" \
|
|
-H "X-Forwarded-Proto: https" \
|
|
"http://127.0.0.1:8080/realms/master/.well-known/openid-configuration" \
|
|
-o "${LOCK_DIR}/openid-configuration.json" 2> "$log_file" && \
|
|
grep -Eq '"issuer"[[:space:]]*:[[:space:]]*"https://'"${FQHN_HOSTNAME//./\.}"'/realms/master"' \
|
|
"${LOCK_DIR}/openid-configuration.json" ; then
|
|
echo_ok
|
|
keycloak_service_started=true
|
|
break
|
|
fi
|
|
if [[ ${index} -ge ${_max_secs_waiting} ]]; then
|
|
echo_failed
|
|
journalctl -u keycloak.service -n 50 --no-pager > "$log_file" 2>&1
|
|
fatal "Keycloak did not become healthy within ${_max_secs_waiting} seconds or returned an unexpected issuer. The old installation remains at '${CUR_INSTALL_DIR}'. Do not start it against a possibly migrated database without checking compatibility or restoring '${DB_DUMP_FILE}'. Last log messages:\n$(cat "$log_file")"
|
|
fi
|
|
(( index++ ))
|
|
sleep 1
|
|
done
|
|
|
|
clean_up 0
|