# -o pipefail: Causes a pipeline to return the exit status of the last command that failed.
set -euo pipefail
#
# Required environment variables (no defaults, fail fast if missing):
# production mode -> KC_PROD_DB_PASSWORD
# development mode -> KC_DEV_DB_PASSWORD
# Set them in the environment (or a root-only sourced secrets file), not in this script.
#
# Check if the user has specified 'production' or 'development' mode
mode=${1:-development}
# Echo the selected mode to the user
echo"Running in $mode mode"
# Define variables based on the selected mode
if[["$mode"=="production"]];then
BASE_NAME="keycloak"
REMOTE_DB_USER="KeyCloakAdmin"# The database user for backups
REMOTE_DB_PASSWORD="${KC_PROD_DB_PASSWORD:?Set KC_PROD_DB_PASSWORD in the environment before running (production DB backup password)}"
else
BASE_NAME="keycloakdev"
REMOTE_DB_USER="KeyCloakDevAdmin"# The database user for development
REMOTE_DB_PASSWORD="${KC_DEV_DB_PASSWORD:?Set KC_DEV_DB_PASSWORD in the environment before running (development DB backup password)}"
fi
destination_folder="/opt/$BASE_NAME"# Location of the current Keycloak version for production
REMOTE_DB_NAME="$BASE_NAME"# The name of the database for production
REMOTE_BACKUP_PATH="/var/backups/$BASE_NAME/backup_$(date +'%Y%m%d_%H%M%S').bak"# Path on the remote server where the backup will be saved for production
SERVICE_NAME="$BASE_NAME"# The name of the service for production
#Remote Database Host
REMOTE_DB_HOST="dotnet.linux.lead.nl"
# Directory to store the backup of the current Keycloak version
backup_folder="/var/tmp/$BASE_NAME/backup_$(date +'%Y%m%d_%H%M%S')"# Temp location where the current version is backed up
# Directory to store the downloaded Keycloak .zip file
zip_folder="/var/tmp/$BASE_NAME/zip"# Temp location where the new version in .zip format is downloaded
# Directory to extract the downloaded Keycloak zip file
installation_folder="/var/tmp/$BASE_NAME/install"# Temp location where the downloaded .zip is extracted
# Define the current and target versions of Keycloak
target_version="26.2.1"# The new version of Keycloak
# URL to download the target version of Keycloak
download_url="https://github.com/keycloak/keycloak/releases/download/$target_version/keycloak-$target_version.zip"# Url where the new version can be downloaded
# Function to handle errors
# This function will print the error message and exit the script
echo_error_and_exit(){
echo"Error: $1" >&2
exit1
}
# Function to get user consent
# This function will prompt the user for consent before proceeding with an action
get_user_consent(){
localmessage="$1"
read -p "$message [y/n]: " consent
if[["$consent" !="y"]];then
echo"User aborted operation."
exit1
fi
}
# Function to check and create directories if they do not exist
# Creates the directory path if it does not exist, and sets appropriate permissions
check_directories_create(){
localdirectory_path="$1"
echo"Creating directory: $directory_path"
mkdir -p "$directory_path"|| echo_error_and_exit "Failed to create directory $directory_path"
sudo chmod -R 755"$directory_path"
sudo chown -R $USER:$USER"$directory_path"
}
# Function to backup the Keycloak database
# Connects to the remote SQL Server and creates a backup of the Keycloak database
backup_keycloak_database(){
get_user_consent "Do you want to proceed with backing up the Keycloak database?"
# SQL Server backup command
BACKUP_COMMAND="BACKUP DATABASE [$REMOTE_DB_NAME] TO DISK = N'$REMOTE_BACKUP_PATH' WITH NOFORMAT, NOINIT, NAME = N'$REMOTE_DB_NAME-full', SKIP, NOREWIND, NOUNLOAD, STATS = 10"
# Command to connect to the remote SQL Server and execute the backup
# Ensure all necessary configurations and themes are in place in the installation folder
get_user_consent "Do you want to prepare the new Keycloak version for deployment?"
cp -rf "$backup_folder/$BASE_NAME/conf""$installation_folder/keycloak-$target_version/"|| echo_error_and_exit "Failed to restore configuration files to the installation folder."
cp -rf "$backup_folder/$BASE_NAME/themes""$installation_folder/keycloak-$target_version/"|| echo_error_and_exit "Failed to restore themes to the installation folder."
cp -rf "$backup_folder/$BASE_NAME/providers""$installation_folder/keycloak-$target_version/"|| echo_error_and_exit "Failed to restore provider files to the installation folder."
echo"Configuration, themes, and providers successfully added to the new installation."
# Stop the running Keycloak service to proceed with the update
get_user_consent "Do you want to stop the Keycloak service ($SERVICE_NAME)?"
sudo systemctl stop $SERVICE_NAME|| echo_error_and_exit "Failed to stop Keycloak service."
echo"Keycloak service stopped successfully."
# Deploy the new Keycloak version
# Remove the current Keycloak version from the destination folder and copy over the new version
get_user_consent "Do you want to deploy the new Keycloak version to the destination folder ($destination_folder)?"
rm -rf "$destination_folder"/* || echo_error_and_exit "Failed to clear $destination_folder."
echo"Successfully cleared $destination_folder."
cp -rfp "$installation_folder/keycloak-$target_version/"* "$destination_folder"|| echo_error_and_exit "Failed to copy new Keycloak version to the destination folder."
echo"Successfully deployed the new Keycloak version to $destination_folder. mainting ownership"
# Rebuild Keycloak (production only)
# In production Keycloak runs optimized, so restored custom providers (e.g. the
# licence mapper) and config changes only take effect after an explicit build.
# Development runs with start-dev, which augments automatically, so no build there.
if[["$mode"=="production"]];then
get_user_consent "Do you want to run 'kc.sh build' so custom providers are included?"