Compare commits

...
12 Commits
12 changed files with 6907 additions and 654 deletions
+2102
View File
File diff suppressed because it is too large Load Diff
+788
View File
@@ -0,0 +1,788 @@
#!/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/mattermost.conf"
LOCK_DIR="/tmp/$(basename $0).$$.LOCK"
log_file="${LOCK_DIR}/${script_name%%.*}.log"
backup_date="$(date +%Y-%m-%d-%H%M)"
# ----------
# Base Function(s)
# ----------
clean_up() {
if [[ -f "$_backup_crontab_file" ]]; then
echononl "(Re)Install previously saved crontab from '$_backup_crontab_file'.."
crontab $_backup_crontab_file >> $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
error "$(cat $log_file)"
fi
fi
# 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(){
echo ""
if $terminal ; then
echo -e " [ \033[31m\033[1mFatal\033[m ] $*"
else
echo -e " [ Fatal ] $*"
fi
echo ""
if $terminal ; then
echo -e " \033[1mScript terminated\033[m.."
else
echo -e " Script terminated.."
fi
echo ""
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 " [ Warning ] $*"
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// /}"
}
# ----------
# - Jobhandling
# ----------
# - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM
# -
trap clean_up 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_MATTERMOST_USER="mattermost"
DEFAULT_MATTERMOST_GROUP="mattermost"
DEFAULT_DB_TYPE="pgsql"
DEFAULT_MATTERMOST_BASE_INSTALL_PATH="/opt"
DEFAULT_MATTERMOST_TMP_DIR="/tmp"
if [[ -f "$conf_file" ]]; then
source "$conf_file"
else
fatal "No configuration file '$conf_file' present.\n
In upgrade mode a configuration file is required!"
fi
[[ -n "$FQHN_HOSTNAME" ]] && DEFAULT_FQHN_HOSTNAME="$FQHN_HOSTNAME"
if [[ -z "$DB_TYPE" ]] ; then
fatal "Missing database type (DB_TYPE)!"
fi
if [[ -z "$DB_NAME" ]] ; then
fatal "Missing database name (DB_NAME)!"
fi
if [[ -z "$DB_USER" ]] ; then
fatal "Missing database user (DB_USER)!"
fi
if [[ -z "$DB_PASS" ]] ; then
fatal "Missing database password (DB_PASS)!"
fi
[[ -n "$MATTERMOST_BASE_INSTALL_PATH" ]] && DEFAULT_MATTERMOST_BASE_INSTALL_PATH="$MATTERMOST_BASE_INSTALL_PATH"
[[ -n "$MATTERMOST_TMP_DIR" ]] && DEFAULT_MATTERMOST_TMP_DIR="$MATTERMOST_TMP_DIR"
[[ -n "$MATTERMOST_USER" ]] && DEFAULT_MATTERMOST_USER="$MATTERMOST_USER"
if [[ -n "$MATTERMOST_GROUP" ]]; then
DEFAULT_MATTERMOST_GROUP="$MATTERMOST_GROUP"
else
DEFAULT_MATTERMOST_GROUP="$DEFAULT_MATTERMOST_USER"
fi
echo -e "\033[32m--\033[m"
echo ""
echo "Version to upgrade Mattermost Server"
echo ""
echo " see: https://mattermost.com/download/"
echo ""
echo ""
MM_NEW_VERSION=
while [ "X$MM_NEW_VERSION" = "X" ]
do
echononl "New Mattermost Server Version: "
read MM_NEW_VERSION
if [ "X$MM_NEW_VERSION" = "X" ]; then
echo -e "\n\t\033[33m\033[1mA Version number is required!\033[m\n"
fi
done
DOWNLOAD_ARCHIVE="mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz"
DOWNLOAD_URL="https://releases.mattermost.com/${MM_NEW_VERSION}/${DOWNLOAD_ARCHIVE}"
echo -e "\033[32m--\033[m"
echo ""
echo "Base path of current mattermost installation."
echo ""
echo -e " The install directory is everything before the first occurrence "
echo -e " of the string \e[3m/mattermost\e[0m."
echo ""
echo ""
MATTERMOST_BASE_INSTALL_PATH=
if [[ -n "$DEFAULT_MATTERMOST_BASE_INSTALL_PATH" ]]; then
while [[ "X${MATTERMOST_BASE_INSTALL_PATH}" = "X" ]]; do
echononl "Base installation path [${DEFAULT_MATTERMOST_BASE_INSTALL_PATH}]: "
read MATTERMOST_BASE_INSTALL_PATH
if [[ "X${MATTERMOST_BASE_INSTALL_PATH}" = "X" ]]; then
MATTERMOST_BASE_INSTALL_PATH=$DEFAULT_MATTERMOST_BASE_INSTALL_PATH
fi
if [[ ! -d "${MATTERMOST_BASE_INSTALL_PATH}/mattermost" ]]; then
echo -e "\n\tGiven Path does not contain a mattermost installation"
MATTERMOST_BASE_INSTALL_PATH=
fi
done
else
while [[ "X${MATTERMOST_BASE_INSTALL_PATH}" = "X" ]]; do
echononl "Base installation path: "
read MATTERMOST_BASE_INSTALL_PATH
if [[ "X${MATTERMOST_BASE_INSTALL_PATH}" = "X" ]]; then
echo -e "\n\t\033[33m\033[1mBase installation path of current installation is reqired\033[m\n"
fi
if [[ ! -d "${MATTERMOST_BASE_INSTALL_PATH}/mattermost" ]]; then
echo -e "\n\tGiven Path does not contain a mattermost installation"
MATTERMOST_BASE_INSTALL_PATH=
fi
done
fi
MATTERMOST_CURRENT_VERSION="$(${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost version 2> /dev/null | grep -E "^Version:" | cut -d' ' -f2)"
MATTERMOST_CURRENT_BUILD_NUMBER="$(${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost version 2> /dev/null | grep -E "^Build Number:" | cut -d' ' -f3)"
echo -e "\033[32m--\033[m"
echo ""
echo "Give TMP directory for Downlaoding and extracting mattermost sources.."
echo ""
echo ""
MATTERMOST_TMP_DIR=
if [[ -n "$DEFAULT_MATTERMOST_TMP_DIR" ]]; then
while [[ "X${MATTERMOST_TMP_DIR}" = "X" ]]; do
echononl "TMP directory [${DEFAULT_MATTERMOST_TMP_DIR}]: "
read MATTERMOST_TMP_DIR
if [[ "X${MATTERMOST_TMP_DIR}" = "X" ]]; then
MATTERMOST_TMP_DIR=$DEFAULT_MATTERMOST_TMP_DIR
fi
if [[ ! -d "${MATTERMOST_TMP_DIR}" ]]; then
echo -e "\n\tnGiven TMP Directory \033[33m\033[1m$MATTERMOST_TMP_DIR\033[m does not exist!\n"
MATTERMOST_TMP_DIR=
fi
done
else
while [[ "X${MATTERMOST_TMP_DIR}" = "X" ]]; do
echononl "TMP directory: "
read MATTERMOST_TMP_DIR
if [[ "X${MATTERMOST_TMP_DIR}" = "X" ]]; then
echo -e "\n\t\033[33m\033[1mA TMP directory is required!\033[m\n"
continue
fi
if [[ ! -d "${MATTERMOST_TMP_DIR}" ]]; then
echo -e "\n\tGiven TMP Directory \033[33m\033[1m$MATTERMOST_TMP_DIR\033[m does not exist!\n"
MATTERMOST_TMP_DIR=""
fi
done
fi
FQHN_HOSTNAME=
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert full qualified hostname for Mattermost 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%%.*}"
echo ""
echo "--"
echo ""
echo "Enter user and group for Mattermost Service."
echo ""
MATTERMOST_USER=
while [ "X$MATTERMOST_USER" = "X" ]
do
echononl "Mattermost user [${DEFAULT_MATTERMOST_USER}]: "
read MATTERMOST_USER
if [ "X$MATTERMOST_USER" = "X" ]; then
MATTERMOST_USER=$DEFAULT_MATTERMOST_USER
fi
done
MATTERMOST_GROUP=
while [ "X$MATTERMOST_GROUP" = "X" ]
do
echononl "Mattermost group [$DEFAULT_MATTERMOST_GROUP]: "
read MATTERMOST_GROUP
if [ "X$MATTERMOST_GROUP" = "X" ]; then
MATTERMOST_GROUP=$DEFAULT_MATTERMOST_GROUP
fi
done
if [[ "$DB_TYPE" = "mysql" ]] ; then
if [[ -n "$MYSQL_CREDENTIAL_ARGS" ]] ; then
if ! $(mysql $MYSQL_CREDENTIAL_ARGS -N -s -e 'quit' > /dev/null 2>&1) ; then
fatal "Parameter MYSQL_CREDENTIAL_ARGS is given, but a connection to MySQL Service failed.!"
fi
USE_MYSQL_CREDENTIAL_ARGS=true
else
USE_MYSQL_CREDENTIAL_ARGS=false
_MYSQL_ROOT_PW=""
echo ""
echo -e "\033[32m--\033[m"
echo ""
echo "Insert root password of MySQL Database Service"
echo ""
while [ "X${_MYSQL_ROOT_PW}" = "X" ]; do
echononl "Passworteingabe: "
read -s _MYSQL_ROOT_PW
if [ "X${_MYSQL_ROOT_PW}" = "X" ]; then
echo -e "\n\t\033[33m\033[1mPassworteingabe erforderlich!\033[m\n"
continue
fi
if $(pgrep mysqld_safe > /dev/null 2>&1) || $(pgrep mysqld > /dev/null 2>&1); then
if $(mysql --user="root" --password="$_MYSQL_ROOT_PW" -N -s -e 'quit' > /dev/null 2>&1) ; then
MYSQL_ROOT_PW=$_MYSQL_ROOT_PW
else
echo -e "\n\t\033[33m\033[1mFalsches Passwort\033[m\n"
_MYSQL_ROOT_PW=""
fi
else
fatal "MySQL seems not be running. Start MySQL Service and try installing mattermost again."
fi
done
fi
fi
blank_line
blank_line
echo -e "\033[32mStart upgrade script for Mattermost Server with the following parameters\033[m"
echo ""
echo -e " Mattermost current Server Version.: $MATTERMOST_CURRENT_VERSION"
echo -e " Mattermost current Build Number...: $MATTERMOST_CURRENT_BUILD_NUMBER"
echo ""
echo -e " Mattermost New Server Version.....: \033[33m\033[1m$MM_NEW_VERSION\033[m"
echo ""
echo -e " Full qualified Hostname...........: $FQHN_HOSTNAME"
echo -e " Hostname..........................: $HOSTNAME"
echo ""
echo -e " Base path of installation.........: $MATTERMOST_BASE_INSTALL_PATH"
echo ""
echo -e " TMP directory ....................: $MATTERMOST_TMP_DIR"
echo ""
echo -e " Mattermost user...................: $MATTERMOST_USER"
echo -e " Mattermost group..................: $MATTERMOST_GROUP"
echo ""
echo ""
if [[ "${DB_TYPE}" = "pgsql" ]] ; then
echo -e " Database Type.....................: PostgreSQL"
else
echo -e " Database Type.....................: MySQL"
fi
echo ""
if [[ "${DB_TYPE}" = "mysql" ]]; then
if $USE_MYSQL_CREDENTIAL_ARGS ; then
echo -e " MYSQL_CREDENTIAL_ARGS.............: $MYSQL_CREDENTIAL_ARGS"
else
echo -e " Root password MySQL...............: **"
fi
fi
echo ""
echo -e " Database Name.....................: $DB_NAME"
echo -e " Database User.....................: $DB_USER"
echo -e " Database Password.................: $DB_PASS"
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..
blank_line
blank_line
if ! $USE_MYSQL_CREDENTIAL_ARGS ; then
MYSQL_CREDENTIAL_ARGS="--user='root' --password=$_MYSQL_ROOT_PW"
if ! $(mysql $MYSQL_CREDENTIAL_ARGS -N -s -e 'quit' > /dev/null 2>&1) ; then
fatal "Parameter MYSQL_CREDENTIAL_ARGS is given, but a connection to MySQL Service failed.!"
fi
fi
blank_line
echo -e "\033[37m\033[1mSome pre-installation stuff..\033[m"
blank_line
echononl "Download version \033[1m${MM_NEW_VERSION}\033[m of the Mattermost Server.."
if [[ ! -f "${working_dir}/mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz" ]]; then
wget -P ${working_dir} $DOWNLOAD_URL > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
else
echo_skipped
fi
# - Deaktiviere Cronjobs
# -
_backup_crontab_file=/tmp/crontab_root.${backup_date}
echononl "Backup Crontab to '$_backup_crontab_file'"
crontab -l > $_backup_crontab_file 2> $log_file
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fatal "$(cat $log_file)"
fi
echononl "Remove crontab for root.."
crontab -r > $log_file 2>&1
if [[ $? -eq 0 ]]; then
echo_ok
else
echo_failed
fatal "$(cat $log_file)"
fi
echononl "Extract the Mattermost Server files into TMP directory.."
tar -xf ${working_dir}/mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz \
-C ${MATTERMOST_TMP_DIR} --transform='s,^[^/]\+,\0-upgrade,'
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
echononl "Stop Mattermost Service.."
if $(systemctl is-active --quiet service mattermost.service) ; then
systemctl stop mattermost.service > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
else
echo_skipped
fi
echononl "Backup mattermost database.."
if [[ "${DB_TYPE}" = "mysql" ]]; then
mysqldump --login-path=local --opt $DB_NAME \
> ${MATTERMOST_BASE_INSTALL_PATH}/${DB_NAME}-${backup_date}.sql 2> $log_file
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
else
pg_dump -U ${DB_USER} -F p -c ${DB_NAME} -f ${MATTERMOST_BASE_INSTALL_PATH}/${DB_NAME}-${backup_date}.sql 2> $log_file
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
fi
echononl "Backup mattermost installation directory.."
cp -ra ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/ \
${MATTERMOST_BASE_INSTALL_PATH}/mattermost-back-${backup_date}/ > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
echo
echo -e "\033[37m\033[1mUpgrade Mattermost to version $MM_NEW_VERSION ..\033[m"
echo
echononl "Remove all files except \e[3mspecial directories\e[0m from within the current mattermost directory."
find ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/ ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/ \
-mindepth 1 -maxdepth 1 \! \( -type d \( -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/plugins \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/config \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/logs \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/plugins \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/data \) -prune \) | sort | sudo xargs rm -r > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
echononl "Change ownership of the new files before copying them.."
chown -hR ${MATTERMOST_USER}:${MATTERMOST_GROUP} ${MATTERMOST_TMP_DIR}/mattermost-upgrade/ > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
echononl "Copy the new files to your install directory.."
cp -an ${MATTERMOST_TMP_DIR}/mattermost-upgrade/. ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/ > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
# Activate the CAP_NET_BIND_SERVICE capability to allow the new Mattermost binary
# to bind to low ports.
#
echononl "Allow the new Mattermost binary to bind to low ports.."
setcap cap_net_bind_service=+ep ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
blank_line
echo -e "\033[37m\033[1mSome post-installation stuff..\033[m"
blank_line
echononl "Remove the temporary files.."
rm -r ${MATTERMOST_TMP_DIR}/mattermost-upgrade/ > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
else
echo_ok
fi
echononl "Start Mattermost Service"
systemctl start mattermost.service > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
else
echo_ok
fi
clean_up 0
Binary file not shown.
+691
View File
@@ -0,0 +1,691 @@
# Mattermost OIDC Mobile Bridge
## Zweck
Diese Dokumentation beschreibt die Installation und Konfiguration der `mobile-bridge` aus dem Projekt `mattermost-oidc` für eine native Mattermost-Mobile-App.
Die Bridge wird benötigt, wenn Mattermost für die Anmeldung das Plugin `mattermost-oidc` verwendet, die native Mobile-App aber den eingebauten Mattermost-OpenID-Endpunkt erwartet. Die Bridge verändert Mattermost selbst nicht. Sie fängt nur zwei HTTP-Endpunkte ab:
- `/api/v4/config/client`
- `/oauth/openid/mobile_login`
Für die native Mattermost-App wird in der Client-Konfiguration `EnableSignUpWithOpenId=true` signalisiert. Der Mobile-Login wird anschließend zum `mattermost-oidc`-Plugin umgeleitet.
Web- und Desktop-Clients bleiben unverändert.
## Versions- und Umgebungsvariablen
Die Anleitung ist bewusst versionsunabhängig aufgebaut. Vor Beginn werden die für die jeweilige Installation gültigen Versionen, URLs und Pfade einmal in der aktuellen Root-Shell gesetzt. Die nachfolgenden Befehle verwenden diese Variablen.
```bash
export MM_VER="11.7.11"
export MM_OIDC_VER="0.6.1"
export MM_SITE_URL="https://mm.nd.digital"
export MM_SRC_BASE="/usr/local/src/mattermost-oidc"
export MM_OIDC_REPO="https://github.com/server-camp/mattermost-oidc-plugin.git"
export MM_OIDC_SRC="${MM_SRC_BASE}/mattermost-oidc-plugin-${MM_OIDC_VER}"
export MM_UPSTREAM="http://127.0.0.1:8065"
export MM_BRIDGE_LISTEN="127.0.0.1:8066"
export MM_BRIDGE_BIN_DIR="/usr/local/sbin"
export MM_BRIDGE_BIN="${MM_BRIDGE_BIN_DIR}/mattermost-oidc-mobile-bridge-${MM_OIDC_VER}"
export MM_BRIDGE_LINK="${MM_BRIDGE_BIN_DIR}/mattermost-oidc-mobile-bridge"
```
`MM_VER` dokumentiert die aktuell eingesetzte Mattermost-Version. Für Download und Build der Bridge ist insbesondere `MM_OIDC_VER` relevant. Bei einer späteren Aktualisierung wird die gewünschte Version im Variablenblock geändert und der Ablauf mit dem neuen Release wiederholt.
Die hier beschriebene Installation wurde mit den oben beispielhaft eingetragenen Versionen getestet. Weitere Rahmenbedingungen waren Debian 13, nginx als Reverse Proxy, Mattermost auf `127.0.0.1:8065`, die Mobile Bridge auf `127.0.0.1:8066` und Keycloak als OIDC-Provider.
Die Bridge benötigt **kein eigenes OIDC-Client-Secret**. Client-ID, Client-Secret und Kommunikation mit dem OIDC-Provider bleiben Aufgabe des `mattermost-oidc`-Plugins.
## Funktionsweise
Der relevante Ablauf ist:
```text
Mattermost Mobile App
|
| GET /api/v4/config/client
v
nginx
|
+--> mobile-bridge :8066
|
+--> Mattermost :8065
|
+--> bei Mobile User-Agent:
EnableSignUpWithOpenId=true
Mobile App
|
| /oauth/openid/mobile_login?redirect_to=mmauth://callback
v
nginx
|
+--> mobile-bridge :8066
|
+--> 302 /plugins/mattermost-oidc/oauth2/connect
?mobile_redirect=mmauth://callback
|
v
Keycloak
|
v
/plugins/mattermost-oidc/oauth2/callback
|
v
mmauth://callback
|
v
Mattermost App
```
Alle anderen Requests, insbesondere REST, WebSocket, Dateien und `/plugins/...`, gehen weiterhin direkt an Mattermost.
## Voraussetzungen
Vor Installation der Bridge müssen folgende Bedingungen erfüllt sein:
1. Das Plugin `mattermost-oidc` ist installiert und aktiviert.
2. Der normale OIDC-Web-Login funktioniert bereits vollständig.
3. Der OIDC-Provider ist korrekt eingerichtet.
4. Die bestehende Redirect-URI des Plugins funktioniert:
`<SiteURL>/plugins/mattermost-oidc/oauth2/callback`
5. nginx leitet die normale Mattermost-Site bereits auf `127.0.0.1:8065` weiter.
6. Go ist zum Bauen der Bridge verfügbar.
Die benötigte Go-Version ist nicht in dieser Anleitung fest verdrahtet. Nach dem Download wird sie direkt aus `mobile-bridge/go.mod` abgelesen. Falls die Debian-Standardversion nicht ausreicht, kann eine passende Go-Version beispielsweise aus den Debian-Backports verwendet werden.
## 1. Quellcode herunterladen
Das Repository wird versionsbezogen unter `MM_SRC_BASE` abgelegt. Dadurch können mehrere Release-Stände parallel vorhanden sein und die Herkunft einer installierten Binary bleibt nachvollziehbar.
Arbeitsverzeichnis anlegen:
```bash
mkdir -p "$MM_SRC_BASE"
```
Gewünschten Release-Tag direkt in ein versionsbezogenes Verzeichnis klonen:
```bash
git clone --branch "v${MM_OIDC_VER}" --depth 1 \
"$MM_OIDC_REPO" \
"$MM_OIDC_SRC"
```
Ausgecheckten Stand kontrollieren:
```bash
cd "$MM_OIDC_SRC"
git status
git describe --tags --exact-match
```
Bei einem direkt ausgecheckten Release-Tag ist ein `detached HEAD` normal. `git describe --tags --exact-match` sollte `v${MM_OIDC_VER}` ausgeben.
Die Mobile Bridge befindet sich anschließend unter:
```text
${MM_OIDC_SRC}/mobile-bridge
```
## 2. Go installieren
Benötigte Go-Version aus dem Release ermitteln:
```bash
awk '/^go / {print "benötigte Go-Version:", $2}' \
"$MM_OIDC_SRC/mobile-bridge/go.mod"
```
Installierte Version prüfen:
```bash
go version
```
Falls die vorhandene Go-Version nicht ausreicht, eine passende Version installieren. Unter Debian 13 kann - sofern `trixie-backports` bereits konfiguriert ist - beispielsweise verwendet werden:
```bash
apt install -t trixie-backports golang-go
```
Danach erneut prüfen:
```bash
go version
```
## 3. Mobile Bridge bauen
In das Bridge-Verzeichnis wechseln:
```bash
cd "$MM_OIDC_SRC/mobile-bridge"
```
Binary bauen:
```bash
go build -o mobile-bridge .
```
Ergebnis kontrollieren:
```bash
file mobile-bridge
ls -lh mobile-bridge
```
## 4. Bridge vor der Installation manuell testen
Port 8066 sollte zunächst frei sein:
```bash
ss -lntp | grep ':8066'
```
Die Bridge testweise nur auf Loopback starten:
```bash
LISTEN="$MM_BRIDGE_LISTEN" UPSTREAM="$MM_UPSTREAM" ./mobile-bridge
```
Die Bindung an `127.0.0.1` ist beabsichtigt. Die Bridge muss nicht direkt aus dem Internet erreichbar sein; nginx ist der öffentliche Einstiegspunkt.
### Mobile Client-Konfiguration testen
In einem zweiten Terminal:
```bash
curl -s -A 'Mattermost Mobile/' \
http://127.0.0.1:8066/api/v4/config/client |
grep -o '"EnableSignUpWithOpenId":"[^"]*"'
```
Erwartet:
```text
"EnableSignUpWithOpenId":"true"
```
Mit einem Browser-User-Agent:
```bash
curl -s -A 'Mozilla/5.0' \
http://127.0.0.1:8066/api/v4/config/client |
grep -o '"EnableSignUpWithOpenId":"[^"]*"'
```
Bei der dokumentierten Konfiguration war das Ergebnis:
```text
"EnableSignUpWithOpenId":"false"
```
Damit ist sichergestellt, dass die Änderung nur für die Mobile-App erfolgt.
### Mobile-Login-Redirect testen
```bash
curl -si \
'http://127.0.0.1:8066/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback' |
head -20
```
Erwartet wird HTTP 302 mit einem `Location`-Header in Richtung:
```text
/plugins/mattermost-oidc/oauth2/connect?mobile_redirect=mmauth%3A%2F%2Fcallback
```
Danach den manuellen Prozess mit `Ctrl-C` beenden.
## 5. Binary versionsbezogen installieren
Die gebaute Bridge wird mit ihrer Plugin-/Bridge-Version im Dateinamen unter `/usr/local/sbin` installiert. Ein stabiler Symlink ohne Versionsnummer zeigt auf die aktuell aktive Binary. Dadurch kann ein Update oder Rollback durch Umschalten des Symlinks erfolgen, während die systemd-Unit unverändert bleibt.
Binary installieren:
```bash
install -o root -g root -m 755 \
mobile-bridge \
"$MM_BRIDGE_BIN"
```
Stabilen Symlink auf diese Version setzen:
```bash
ln -sfn "$(basename "$MM_BRIDGE_BIN")" "$MM_BRIDGE_LINK"
```
Ergebnis kontrollieren:
```bash
ls -l "$MM_BRIDGE_BIN" "$MM_BRIDGE_LINK"
readlink -f "$MM_BRIDGE_LINK"
```
Beispiel für Version `0.6.1`:
```text
/usr/local/sbin/mattermost-oidc-mobile-bridge-0.6.1
/usr/local/sbin/mattermost-oidc-mobile-bridge -> mattermost-oidc-mobile-bridge-0.6.1
```
## 6. systemd-Service einrichten
Datei anlegen:
```text
/etc/systemd/system/mattermost-oidc-mobile-bridge.service
```
Inhalt:
```ini
[Unit]
Description=Mattermost OIDC Mobile Bridge
After=network.target mattermost.service
Requires=mattermost.service
[Service]
Type=simple
User=mattermost
Group=mattermost
Environment=LISTEN=127.0.0.1:8066
Environment=UPSTREAM=http://127.0.0.1:8065
ExecStart=/usr/local/sbin/mattermost-oidc-mobile-bridge
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target
```
`ExecStart` verweist bewusst auf den versionsunabhängigen Symlink. Bei einem Update muss die Unit-Datei deshalb nicht geändert werden.
Konfiguration laden und prüfen:
```bash
systemctl daemon-reload
systemd-analyze verify /etc/systemd/system/mattermost-oidc-mobile-bridge.service
```
Dienst zunächst nur starten:
```bash
systemctl start mattermost-oidc-mobile-bridge.service
```
Status prüfen:
```bash
systemctl status mattermost-oidc-mobile-bridge.service
ss -lntp | grep ':8066'
```
Erwartet wird ein Listener ausschließlich auf:
```text
127.0.0.1:8066
```
Nach erfolgreichem End-to-End-Test den Autostart aktivieren:
```bash
systemctl enable mattermost-oidc-mobile-bridge.service
```
Kontrolle:
```bash
systemctl is-enabled mattermost-oidc-mobile-bridge.service
systemctl is-active mattermost-oidc-mobile-bridge.service
```
Erwartet:
```text
enabled
active
```
## 7. nginx konfigurieren
In der dokumentierten Installation ist die aktive Konfiguration:
```text
/etc/nginx/sites-available/mm.nd.digital.conf
```
mit Symlink unter `sites-enabled`.
Vor der Änderung ein Backup der realen Datei anlegen, nicht nur des Symlinks.
Vor den allgemeinen Mattermost-`location`-Blöcken werden zwei Exact-Match-Locations eingefügt:
```nginx
# Mattermost OIDC Mobile Bridge
location = /api/v4/config/client {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8066;
}
location = /oauth/openid/mobile_login {
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_pass http://127.0.0.1:8066;
}
```
Die vorhandenen WebSocket- und Catch-all-Locations bleiben unverändert und zeigen weiterhin direkt auf Mattermost.
Die Exact-Match-Locations sind wichtig: Nur diese beiden Endpunkte sollen über die Bridge laufen.
Konfiguration prüfen:
```bash
nginx -t
```
Bei erfolgreicher Prüfung:
```bash
systemctl reload nginx
```
## 8. Öffentliche Endpunkte testen
### Mobile User-Agent
```bash
curl -s -A 'Mattermost Mobile/' \
${MM_SITE_URL}/api/v4/config/client |
grep -o '"EnableSignUpWithOpenId":"[^"]*"'
```
Erwartet:
```text
"EnableSignUpWithOpenId":"true"
```
### Browser User-Agent
```bash
curl -s -A 'Mozilla/5.0' \
${MM_SITE_URL}/api/v4/config/client |
grep -o '"EnableSignUpWithOpenId":"[^"]*"'
```
Bei der dokumentierten Installation:
```text
"EnableSignUpWithOpenId":"false"
```
### Mobile Login
```bash
curl -si \
"${MM_SITE_URL}/oauth/openid/mobile_login?redirect_to=mmauth%3A%2F%2Fcallback" |
head -20
```
Erwartet wird HTTP 302 auf den Connect-Endpunkt des OIDC-Plugins.
## 9. End-to-End-Test mit der Mattermost-App
In der nativen Mattermost-App:
1. Server aus `MM_SITE_URL` hinzufügen (im dokumentierten Beispiel `https://mm.nd.digital`).
2. Die App muss zusätzlich zur normalen Anmeldung einen Button **Log in with OIDC** anzeigen.
3. OIDC-Login auswählen.
4. Bei Keycloak anmelden.
5. Nach erfolgreicher Authentifizierung muss die App über `mmauth://callback` zurückkehren.
6. Team und Channels müssen anschließend geladen werden.
## 10. Wichtiger Sonderfall: Default Team und erlaubte E-Mail-Domains
Das `mattermost-oidc`-Plugin kann neu angelegte OIDC-Benutzer automatisch einem **Default Team** hinzufügen.
In der dokumentierten Installation ist im Plugin konfiguriert:
```text
Default Team: nd
```
Das Team `nd` erlaubt jedoch nur Benutzer mit einer bestimmten E-Mail-Domain:
```text
nd-online.de
```
Beim Test wurde ein OIDC-Benutzer mit einer anderen Domain erfolgreich angelegt und authentifiziert, konnte aber nicht automatisch dem Team `nd` hinzugefügt werden. Mattermost protokollierte sinngemäß:
```text
Failed to add user to default team
The user cannot be added as the domain associated with the account is not permitted.
```
Das Fehlerbild in der Mobile-App war:
```text
Konnte nicht geladen werden
```
Das Profil des angemeldeten Benutzers war trotzdem erreichbar. Ursache war **nicht die Mobile Bridge und nicht der OIDC-Token**, sondern die fehlende Team-Mitgliedschaft.
### Diagnose
Team-Domain aus PostgreSQL nur lesend prüfen:
```bash
su - postgres -c \
"psql -d mattermost -c \"SELECT name, displayname, type, allowopeninvite, alloweddomains FROM teams WHERE name='nd';\""
```
Alternativ in der System Console:
```text
User Management
-> Teams
-> ND
-> Team Management
-> Only specific email domains can join this team
```
Wenn ein Testbenutzer aus einer anderen Domain verwendet wird, sollte die Domain-Beschränkung **nicht dauerhaft aufgeweicht** werden.
Für den dokumentierten Test wurde die zusätzliche Testdomain kurzzeitig in der kommagetrennten Domainliste zugelassen, der Testbenutzer administrativ zum Team hinzugefügt und die Domainliste anschließend wieder auf den ursprünglichen Wert zurückgesetzt.
## 11. Logs und Fehlersuche
### Bridge
Status:
```bash
systemctl status mattermost-oidc-mobile-bridge.service
```
Journal:
```bash
journalctl -u mattermost-oidc-mobile-bridge.service
```
Für eine gezielte Fehlersuche kann die Bridge mit `DEBUG=1` betrieben werden. Dies sollte nur bei Bedarf aktiviert werden, da dann beobachtete User-Agents protokolliert werden.
### Mattermost
```bash
journalctl -u mattermost.service
```
Bei OIDC-Problemen insbesondere nach Meldungen mit folgenden Begriffen suchen:
```text
oidc
mobile
session
mattermost-oidc
```
### Typische Fehlerbilder
**Kein OIDC-Button in der App**
Prüfen:
- `mattermost-oidc` ist aktiviert.
- Web-OIDC funktioniert.
- `/api/v4/config/client` wird für Mobile User-Agents über die Bridge geleitet.
- `EnableSignUpWithOpenId` ist für `Mattermost Mobile/` auf `true`.
- nginx wurde nach der Änderung erfolgreich neu geladen.
**OIDC-Button erscheint, Login startet nicht korrekt**
Prüfen:
- `/oauth/openid/mobile_login` liefert HTTP 302.
- Ziel ist `/plugins/mattermost-oidc/oauth2/connect`.
- nginx routet exakt diesen Endpunkt auf Port 8066.
**Login bei Keycloak erfolgreich, App lädt aber kein Team**
Prüfen:
- Wurde der Benutzer in Mattermost angelegt?
- Ist der Benutzer Mitglied eines Teams?
- Ist im OIDC-Plugin ein `Default Team` konfiguriert?
- Verhindert `AllowedDomains` des Teams das automatische Hinzufügen?
## 12. Umgebungsvariablen der Bridge
Die Bridge unterstützt laut Projekt-README folgende Variablen:
| Variable | Standard | Zweck |
|---|---|---|
| `LISTEN` | `:8066` | Listen-Adresse |
| `UPSTREAM` | `http://127.0.0.1:8065` | Mattermost-Upstream |
| `PLUGIN_CONNECT_PATH` | `/plugins/mattermost-oidc/oauth2/connect` | Connect-Endpunkt des Plugins |
| `PLUGIN_CONFIG_PATH` | `/plugins/mattermost-oidc/api/v1/config` | öffentliche Plugin-Konfiguration |
| `MOBILE_UA_MATCH` | `Mattermost Mobile/` | Erkennung der nativen App |
| `OPENID_BUTTON_TEXT` | leer / automatisch | optionaler fester Button-Text |
| `OPENID_BUTTON_COLOR` | leer / automatisch | optionale feste Button-Farbe |
| `DEBUG` | leer | bei `1` User-Agent-Logging |
In der dokumentierten Installation werden nur `LISTEN` und `UPSTREAM` explizit gesetzt. Die übrigen Werte bleiben auf den Defaults.
## 13. Update der Bridge
Für ein Update wird die neue Version zunächst im Variablenblock als `MM_OIDC_VER` gesetzt. `MM_OIDC_SRC` und `MM_BRIDGE_BIN` ergeben sich daraus automatisch. Die bisherige versionsbezogene Binary bleibt zunächst erhalten.
Beispiel: Variablenblock mit der gewünschten neuen Version erneut setzen und anschließend den Release wie in Abschnitt 1 herunterladen. Danach:
```bash
cd "$MM_OIDC_SRC/mobile-bridge"
go build -o mobile-bridge .
```
Neue versionsbezogene Binary installieren:
```bash
install -o root -g root -m 755 \
mobile-bridge \
"$MM_BRIDGE_BIN"
```
Vor dem Umschalten kontrollieren:
```bash
file "$MM_BRIDGE_BIN"
ls -lh "$MM_BRIDGE_BIN"
```
Symlink atomar auf die neue Version umstellen und Dienst neu starten:
```bash
ln -sfn "$(basename "$MM_BRIDGE_BIN")" "$MM_BRIDGE_LINK"
systemctl restart mattermost-oidc-mobile-bridge.service
systemctl is-active mattermost-oidc-mobile-bridge.service
readlink -f "$MM_BRIDGE_LINK"
```
Danach die HTTP-Tests und einen Mobile-Login erneut durchführen. Die alte versionsbezogene Binary sollte erst entfernt werden, wenn der neue Stand erfolgreich getestet wurde.
## 14. Rollback
Soll die Bridge wieder entfernt werden:
1. Die beiden Exact-Match-`location`-Blöcke aus nginx entfernen.
2. `nginx -t` ausführen.
3. nginx neu laden.
4. Bridge stoppen und deaktivieren.
5. Optional Unit-Datei und Binary entfernen.
### Rollback auf eine vorherige Bridge-Version
Solange die vorherige versionsbezogene Binary noch vorhanden ist, genügt es, den Symlink zurückzusetzen und den Dienst neu zu starten. Beispiel:
```bash
ln -sfn mattermost-oidc-mobile-bridge-<vorherige-version> \
/usr/local/sbin/mattermost-oidc-mobile-bridge
systemctl restart mattermost-oidc-mobile-bridge.service
readlink -f /usr/local/sbin/mattermost-oidc-mobile-bridge
```
### Bridge vollständig entfernen
```bash
systemctl disable --now mattermost-oidc-mobile-bridge.service
rm -f /etc/systemd/system/mattermost-oidc-mobile-bridge.service
systemctl daemon-reload
rm -f /usr/local/sbin/mattermost-oidc-mobile-bridge
# Versionsbezogene Binaries bei Bedarf anschließend gezielt entfernen.
```
Das `mattermost-oidc`-Plugin und der normale Web-OIDC-Login können dabei unverändert weiterbetrieben werden.
## 15. Sicherheitsaspekte
- Die Bridge nur auf `127.0.0.1:8066` binden.
- Port 8066 nicht öffentlich in der Firewall freigeben.
- Nur die beiden benötigten Exact-Match-Endpunkte über nginx zur Bridge leiten.
- Keine OIDC-Secrets in die systemd-Unit eintragen; die Bridge benötigt keine.
- Client Secret und andere Zugangsdaten nicht in Dokumentationen oder Logs übernehmen.
- Nach Änderungen an OIDC immer Web- und Mobile-Login testen.
- Team-Domain-Beschränkungen nicht nur für einen Test dauerhaft erweitern.
## 16. Abschlusskontrolle
Nach einer vollständigen Installation sollten folgende Prüfungen erfolgreich sein:
```bash
systemctl is-enabled mattermost-oidc-mobile-bridge.service
systemctl is-active mattermost-oidc-mobile-bridge.service
ss -lntp | grep ':8066'
nginx -t
```
Zusätzlich:
```text
Mobile UA -> EnableSignUpWithOpenId=true
Browser UA -> unveränderte Mattermost-Konfiguration
mobile_login -> HTTP 302 zum mattermost-oidc-Plugin
Web-OIDC -> funktioniert
Mobile-OIDC -> funktioniert
Team/Channels -> werden in der App geladen
```
+139
View File
@@ -0,0 +1,139 @@
# Mattermost CLI (mmctl) – Anmeldung & Admin-Nutzerverwaltung
Diese Anleitung beschreibt, wie du `mmctl` per **Login-Modus** (Variante 2) nutzt, statt über den Local-Socket-Modus. Damit brauchst du kein `sudo` und keine Serverkonfiguration anzupassen.
---
## Voraussetzungen
- Mattermost läuft und ist unter einer URL erreichbar (lokal z. B. `http://localhost:8065`)
- Du hast bereits einen bestehenden System-Admin-Account (Username + Passwort)
- `mmctl` ist installiert (z. B. unter `/opt/mattermost/bin/mmctl`)
---
## 1. Bei mmctl anmelden
/opt/mattermost/bin/mmctl auth login http://localhost:8065 \
--name local-admin \
--username <dein-admin-username> \
--password <dein-admin-passwort>
# alternativ: zunächst das passwort in einer Datei speichern und dies dann bei der
# Authentifizierung einlesen:
#
cat << EOF > /tmp/.mm-admin-nd.auth
9-ULw6j-RRZsF./p
EOF
/opt/mattermost/bin/mmctl auth login http://localhost:8065 \
--name local-admin \
--username admin-nd \
--password-file /tmp/.mm-admin-nd.auth
**Parameter-Erklärung:**
| Parameter | Bedeutung
|-------------------------|-----------
| `http://localhost:8065` | URL deines Mattermost-Servers
| `--name local-admin` | Frei wählbarer Name für dieses Login-Profil (wird lokal gespeichert)
| `--username` | Dein bestehender Admin-Benutzername
| `--password` | Dein bestehendes Admin-Passwort
Nach erfolgreichem Login speichert `mmctl` die Session lokal (unter `~/.config/mmctl/`), sodass du dich nicht bei jedem Befehl neu anmelden musst.
**Kein `sudo` nötig** - die Authentifizierung läuft über die normale API, nicht über den geschützten Unix-Socket.
---
## 2. Login prüfen (optional)
/opt/mattermost/bin/mmctl auth list
Zeigt alle gespeicherten Login-Profile. Das aktive Profil ist markiert.
Falls du mehrere Profile hast und wechseln willst:
/opt/mattermost/bin/mmctl auth set local-admin
---
## 3. Neuen System-Admin-Nutzer anlegen
/opt/mattermost/bin/mmctl user create \
--email "l.nienhaus@nd-online.de" \
--username "admin-nd" \
--password "EinSicheresPasswort123!" \
--system-admin
**Parameter-Erklärung:**
| Parameter | Bedeutung
|------------------|----------
| `--email` | E-Mail-Adresse des neuen Nutzers
| `--username` | Gewünschter Benutzername
| `--password` | Startpasswort (sollte sicher sein, Nutzer kann es später ändern)
| `--system-admin` | Vergibt sofort die System-Admin-Rolle
---
## 4. Bestehenden Nutzer nachträglich zum Admin machen
Falls der Nutzer schon existiert und nur die Rolle fehlt:
/opt/mattermost/bin/mmctl roles system_admin <username-oder-email>
---
## 5. Kontrolle: Nutzerliste anzeigen
/opt/mattermost/bin/mmctl user list
Zeigt alle registrierten Nutzer inkl. E-Mail und Rollen.
---
## 6. Abmelden (optional, für saubere Sessions)
/opt/mattermost/bin/mmctl auth clean
Löscht alle gespeicherten Login-Profile.
---
## Troubleshooting
| Fehler | Ursache | Lösung |
|------------------------------------------------- | ------------------------- |---------------------------
| `socket file "/var/tmp/mattermost_local.socket" | mmctl versucht Local Mode | Erst `mmctl auth login`
| doesn't exist` | statt Login-Modus | ausführen (siehe Schritt 1)
------------------------------------------------------------------------------------------------------------
| `Error: You are not logged in` | Session abgelaufen oder | Schritt 1 wiederholen
| | nicht angemeldet |
------------------------------------------------------------------------------------------------------------
| `command not found: mmctl` | mmctl nicht im PATH | Vollen Pfad nutzen, z. B.
| | |`/opt/mattermost/bin/mmctl`
------------------------------------------------------------------------------------------------------------
| Verbindung schlägt fehl (`connection refused`) | Falsche URL oder Server | URL/Port prüfen,
| | läuft nicht | `systemctl status mattermost`
------------------------------------------------------------------------------------------------------------
---
## Kurzreferenz (Cheat Sheet)
# Anmelden
/opt/mattermost/bin/mmctl auth login http://localhost:8065 --name local-admin --username <user> --password <pass>
# Neuen Admin anlegen
/opt/mattermost/bin/mmctl user create --email "<email>" --username "<user>" --password "<pass>" --system-admin
# Bestehenden Nutzer zum Admin machen
/opt/mattermost/bin/mmctl roles system_admin <username-oder-email>
# Nutzerliste anzeigen
/opt/mattermost/bin/mmctl user list
# Abmelden / Session löschen
/opt/mattermost/bin/mmctl auth clean
+131
View File
@@ -0,0 +1,131 @@
# Mattermost CLI (mmctl) – Anmeldung & Admin-Nutzerverwaltung
Diese Anleitung beschreibt, wie du `mmctl` per **Login-Modus** (Variante 2) nutzt, statt über den Local-Socket-Modus. Damit brauchst du kein `sudo` und keine Serverkonfiguration anzupassen.
---
## Voraussetzungen
- Mattermost läuft und ist unter einer URL erreichbar (lokal z. B. `http://localhost:8065`)
- Du hast bereits einen bestehenden System-Admin-Account (Username + Passwort)
- `mmctl` ist installiert (z. B. unter `/opt/mattermost/bin/mmctl`)
---
## 1. Bei mmctl anmelden
```bash
mmctl auth login http://localhost:8065 --name local-admin --username <dein-admin-username> --password <dein-admin-passwort>
```
**Parameter-Erklärung:**
| Parameter | Bedeutung |
|---|---|
| `http://localhost:8065` | URL deines Mattermost-Servers |
| `--name local-admin` | Frei wählbarer Name für dieses Login-Profil (wird lokal gespeichert) |
| `--username` | Dein bestehender Admin-Benutzername |
| `--password` | Dein bestehendes Admin-Passwort |
Nach erfolgreichem Login speichert `mmctl` die Session lokal (unter `~/.config/mmctl/`), sodass du dich nicht bei jedem Befehl neu anmelden musst.
**Kein `sudo` nötig** – die Authentifizierung läuft über die normale API, nicht über den geschützten Unix-Socket.
---
## 2. Login prüfen (optional)
```bash
mmctl auth list
```
Zeigt alle gespeicherten Login-Profile. Das aktive Profil ist markiert.
Falls du mehrere Profile hast und wechseln willst:
```bash
mmctl auth set local-admin
```
---
## 3. Neuen System-Admin-Nutzer anlegen
```bash
mmctl user create \
--email "l.nienhaus@nd-online.de" \
--username "admin-nd" \
--password "EinSicheresPasswort123!" \
--system-admin
```
**Parameter-Erklärung:**
| Parameter | Bedeutung |
|---|---|
| `--email` | E-Mail-Adresse des neuen Nutzers |
| `--username` | Gewünschter Benutzername |
| `--password` | Startpasswort (sollte sicher sein, Nutzer kann es später ändern) |
| `--system-admin` | Vergibt sofort die System-Admin-Rolle |
---
## 4. Bestehenden Nutzer nachträglich zum Admin machen
Falls der Nutzer schon existiert und nur die Rolle fehlt:
```bash
mmctl roles system_admin <username-oder-email>
```
---
## 5. Kontrolle: Nutzerliste anzeigen
```bash
mmctl user list
```
Zeigt alle registrierten Nutzer inkl. E-Mail und Rollen.
---
## 6. Abmelden (optional, für saubere Sessions)
```bash
mmctl auth clean
```
Löscht alle gespeicherten Login-Profile.
---
## Troubleshooting
| Fehler | Ursache | Lösung |
|---|---|---|
| `socket file "/var/tmp/mattermost_local.socket" doesn't exist` | mmctl versucht Local Mode statt Login-Modus | Erst `mmctl auth login` ausführen (siehe Schritt 1) |
| `Error: You are not logged in` | Session abgelaufen oder nicht angemeldet | Schritt 1 wiederholen |
| `command not found: mmctl` | mmctl nicht im PATH | Vollen Pfad nutzen, z. B. `/opt/mattermost/bin/mmctl` |
| Verbindung schlägt fehl (`connection refused`) | Falsche URL oder Server läuft nicht | URL/Port prüfen, `systemctl status mattermost` |
---
## Kurzreferenz (Cheat Sheet)
```bash
# Anmelden
mmctl auth login http://localhost:8065 --name local-admin --username <user> --password <pass>
# Neuen Admin anlegen
mmctl user create --email "<email>" --username "<user>" --password "<pass>" --system-admin
# Bestehenden Nutzer zum Admin machen
mmctl roles system_admin <username-oder-email>
# Nutzerliste anzeigen
mmctl user list
# Abmelden / Session löschen
mmctl auth clean
```
+4
View File
@@ -100,6 +100,10 @@ EOF
#
apt install poppler-utils
# Install ffmpeg
#
apt install ffmpeg
# ---
# 1.) Install Mattermost Service
+14 -8
View File
@@ -17,8 +17,9 @@ server {
}
server {
listen 443 ssl http2;
listen [::]:443 ssl http2;
listen 443 ssl ;
listen [::]:443 ssl ;
http2 on;
server_name @FQHN_HOSTNAME@;
@@ -28,8 +29,6 @@ server {
#
include snippets/letsencrypt-acme-challenge.conf;
#ssl on;
ssl_certificate /var/lib/dehydrated/certs/@FQHN_HOSTNAME@/fullchain.pem;
ssl_certificate_key /var/lib/dehydrated/certs/@FQHN_HOSTNAME@/privkey.pem;
ssl_trusted_certificate /var/lib/dehydrated/certs/@FQHN_HOSTNAME@/chain.pem;
@@ -51,15 +50,24 @@ server {
# omit TLSv1 TLSv1.1
ssl_protocols TLSv1.2 TLSv1.3;
# Enable TLSv1.3's 0-RTT. Use $ssl_early_data when reverse proxying to
# prevent replay attacks.
#
# @see: https://nginx.org/en/docs/http/ngx_http_ssl_module.html#ssl_early_data
ssl_early_data on;
# ECDHE better than DHE (faster) ECDHE & DHE GCM better than CBC (attacks on AES)
# Everything better than SHA1 (deprecated)
#
ssl_ciphers 'ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA256';
ssl_prefer_server_ciphers on;
ssl_ecdh_curve X25519MLKEM768:X25519:prime256v1:secp384r1;
ssl_ciphers ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-ECDSA-CHACHA20-POLY1305:ECDHE-RSA-CHACHA20-POLY1305;
ssl_prefer_server_ciphers off;
# HSTS (ngx_http_headers_module is required) (15768000 seconds = 6 months)
#
add_header Strict-Transport-Security max-age=15768000;
add_header X-Early-Data $tls1_3_early_data;
add_header X-Frame-Options SAMEORIGIN;
# OCSP Stapling ---
# fetch OCSP records from URL in ssl_certificate and cache them
@@ -74,7 +82,6 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
client_body_timeout 60;
@@ -93,7 +100,6 @@ server {
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Frame-Options SAMEORIGIN;
proxy_buffers 256 16k;
proxy_buffer_size 16k;
proxy_read_timeout 600s;
+442 -586
View File
File diff suppressed because it is too large Load Diff
+977
View File
@@ -0,0 +1,977 @@
#!/usr/bin/env bash
script_name="$(basename $(realpath $0))"
working_dir="$(dirname $(realpath $0))"
LOCK_DIR="/tmp/$(basename $0).$$.LOCK"
log_file="${LOCK_DIR}/${script_name%%.*}.log"
backup_date="$(date +%Y-%m-%d-%H%M%S)"
MM_OIDC_REPOSITORY="https://github.com/server-camp/mattermost-oidc-plugin.git"
MM_OIDC_RELEASE_BASE="https://github.com/server-camp/mattermost-oidc-plugin/releases/download"
MM_OIDC_PLUGIN_ID="mattermost-oidc"
MM_SOURCE_BASE="/usr/local/src/mattermost"
MM_INSTALL_DIR="/opt/mattermost"
MM_BIN="${MM_INSTALL_DIR}/bin/mattermost"
MMCTL="${MM_INSTALL_DIR}/bin/mmctl"
MM_CONFIG_FILE="${MM_INSTALL_DIR}/config/config.json"
MM_LOCAL_SOCKET="/var/tmp/mattermost_local.socket"
MM_SERVICE="mattermost.service"
MM_USER="mattermost"
MM_GROUP="mattermost"
INSTALLATION_MODE=""
MM_CURRENT_VERSION=""
MM_NEW_VERSION=""
MM_LATEST_VERSION=""
MM_MIN_SERVER_VERSION=""
MM_SERVER_VERSION=""
MM_BUNDLE=""
MM_BUNDLE_BACKUP=""
MM_ROLLBACK_BUNDLE=""
MM_PREVIOUS_PLUGIN_ENABLED=false
MM_ROLLBACK_REQUIRED=false
# ----------
# Base Function(s)
# ----------
clean_up() {
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(){
echo ""
if $terminal ; then
echo -e " [ \033[31m\033[1mFatal\033[m ] $*"
else
echo -e " [ Fatal ] $*"
fi
echo ""
if $terminal ; then
echo -e " \033[1mScript terminated\033[m.."
else
echo -e " Script terminated.."
fi
echo ""
clean_up 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 " [ Warning ] $*"
fi
echo ""
}
info (){
if $terminal ; then
echo ""
echo -e " [ \033[32m\033[1mInfo\033[m ] $*"
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
}
blank_line() {
if $terminal ; then
echo ""
fi
}
ask_yes_no() {
local question="$1"
local default_answer="${2:-no}"
local answer=""
local prompt="[yes/no]"
if [[ "$default_answer" = "yes" ]]; then
prompt="[yes/no, default: yes]"
elif [[ "$default_answer" = "no" ]]; then
prompt="[yes/no, default: no]"
fi
while true ; do
echononl "$question $prompt: "
read answer
answer="${answer,,}"
[[ -z "$answer" ]] && answer="$default_answer"
case "$answer" in
yes) return 0 ;;
no) return 1 ;;
*) warn "Wrong entry! Please enter 'yes' or 'no'." ;;
esac
done
}
version_ge() {
[[ "$(printf '%s\n%s\n' "$2" "$1" | sort -V | head -1)" = "$2" ]]
}
plugin_state_json() {
"$MMCTL" --local --json plugin list 2>> "$log_file"
}
installed_plugin_version() {
plugin_state_json | python3 -c '
import json, sys
plugin_id = sys.argv[1]
try:
data = json.load(sys.stdin)
except Exception:
raise SystemExit(1)
if isinstance(data, list) and len(data) == 1 and isinstance(data[0], dict):
data = data[0]
def walk(obj):
if isinstance(obj, dict):
if obj.get("id") == plugin_id and obj.get("version"):
print(obj["version"])
raise SystemExit(0)
for value in obj.values():
walk(value)
elif isinstance(obj, list):
for value in obj:
walk(value)
walk(data)
raise SystemExit(2)
' "$MM_OIDC_PLUGIN_ID"
}
plugin_is_enabled() {
plugin_state_json | python3 -c '
import json, sys
plugin_id = sys.argv[1]
try:
data = json.load(sys.stdin)
except Exception:
raise SystemExit(1)
if isinstance(data, list) and len(data) == 1 and isinstance(data[0], dict):
data = data[0]
if not isinstance(data, dict):
raise SystemExit(1)
active = data.get("active")
inactive = data.get("inactive")
if not isinstance(active, list) or not isinstance(inactive, list):
raise SystemExit(1)
for plugin in active:
if isinstance(plugin, dict) and plugin.get("id") == plugin_id:
raise SystemExit(0)
for plugin in inactive:
if isinstance(plugin, dict) and plugin.get("id") == plugin_id:
raise SystemExit(2)
raise SystemExit(1)
' "$MM_OIDC_PLUGIN_ID"
}
restore_release_bundle() {
if [[ -n "$MM_BUNDLE_BACKUP" && -f "$MM_BUNDLE_BACKUP" ]]; then
rm -f "$MM_BUNDLE"
if mv "$MM_BUNDLE_BACKUP" "$MM_BUNDLE" > "$log_file" 2>&1 ; then
MM_BUNDLE_BACKUP=""
return 0
fi
return 1
fi
rm -f "$MM_BUNDLE"
return 0
}
cleanup_prepared_bundles() {
if [[ -n "$MM_ROLLBACK_BUNDLE" ]]; then
rm -f "$MM_ROLLBACK_BUNDLE"
fi
restore_release_bundle
}
rollback_plugin() {
local rollback_failed=false
local restore_command_failed=false
local _rollback_version=""
local _rollback_rc
local _plugin_enabled_rc
blank_line
warn "Mattermost OIDC Plugin installation failed. Trying to restore the previous plugin state."
if [[ "$INSTALLATION_MODE" = "upgrade" ]]; then
echononl "Restore Mattermost OIDC Plugin ${MM_CURRENT_VERSION}.."
if [[ -f "$MM_ROLLBACK_BUNDLE" ]] &&
"$MMCTL" --local plugin add --force "$MM_ROLLBACK_BUNDLE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
restore_command_failed=true
fi
if $MM_PREVIOUS_PLUGIN_ENABLED ; then
echononl "Restore previous plugin state 'enabled'.."
if "$MMCTL" --local plugin enable "$MM_OIDC_PLUGIN_ID" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
restore_command_failed=true
fi
else
echononl "Restore previous plugin state 'disabled'.."
if "$MMCTL" --local plugin disable "$MM_OIDC_PLUGIN_ID" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
restore_command_failed=true
fi
fi
echononl "Verify restored plugin version '${MM_CURRENT_VERSION}'.."
_rollback_version="$(installed_plugin_version 2>/dev/null)"
if [[ "$_rollback_version" = "$MM_CURRENT_VERSION" ]]; then
echo_ok
else
echo_failed
rollback_failed=true
fi
echononl "Verify restored plugin state.."
plugin_is_enabled
_plugin_enabled_rc=$?
if $MM_PREVIOUS_PLUGIN_ENABLED ; then
if [[ $_plugin_enabled_rc -eq 0 ]]; then
echo_ok
else
echo_failed
rollback_failed=true
fi
else
if [[ $_plugin_enabled_rc -eq 2 ]]; then
echo_ok
else
echo_failed
rollback_failed=true
fi
fi
elif [[ "$INSTALLATION_MODE" = "initial-installation" ]]; then
installed_plugin_version > /dev/null 2>&1
_rollback_rc=$?
echononl "Remove newly installed Mattermost OIDC Plugin.."
if [[ $_rollback_rc -eq 2 ]]; then
echo_ok
elif [[ $_rollback_rc -eq 0 ]]; then
if "$MMCTL" --local plugin delete "$MM_OIDC_PLUGIN_ID" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
restore_command_failed=true
fi
else
echo_failed
restore_command_failed=true
fi
echononl "Verify Mattermost OIDC Plugin was removed.."
installed_plugin_version > /dev/null 2>&1
_rollback_rc=$?
if [[ $_rollback_rc -eq 2 ]]; then
echo_ok
else
echo_failed
rollback_failed=true
fi
else
rollback_failed=true
fi
if $rollback_failed ; then
error "Automatic plugin rollback could not fully restore the previous state."
return 1
fi
if $restore_command_failed ; then
warn "One or more rollback commands reported an error, but the previous plugin state was successfully verified."
fi
info "Previous Mattermost OIDC Plugin state was successfully restored."
return 0
}
fatal_with_plugin_rollback() {
local failure_message="$1"
if $MM_ROLLBACK_REQUIRED ; then
if rollback_plugin ; then
MM_ROLLBACK_REQUIRED=false
if [[ -n "$MM_ROLLBACK_BUNDLE" && -f "$MM_ROLLBACK_BUNDLE" ]]; then
echononl "Remove temporary rollback bundle.."
if rm -f "$MM_ROLLBACK_BUNDLE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
warn "Plugin rollback was successful, but temporary rollback bundle '${MM_ROLLBACK_BUNDLE}' could not be removed."
fi
fi
if [[ -n "$MM_BUNDLE_BACKUP" && -f "$MM_BUNDLE_BACKUP" ]]; then
echononl "Remove previous release bundle backup.."
if rm -f "$MM_BUNDLE_BACKUP" > "$log_file" 2>&1 ; then
MM_BUNDLE_BACKUP=""
echo_ok
else
echo_failed
warn "Plugin rollback was successful, but previous release bundle backup '${MM_BUNDLE_BACKUP}' could not be removed."
fi
fi
fatal "${failure_message} The previous plugin state was successfully restored."
else
fatal "${failure_message} Automatic rollback could not fully restore the previous state. Manual intervention is required."
fi
fi
fatal "$failure_message"
}
handle_signal() {
trap - SIGHUP SIGINT SIGTERM
blank_line
warn "Installation interrupted by signal."
if $MM_ROLLBACK_REQUIRED ; then
if rollback_plugin ; then
MM_ROLLBACK_REQUIRED=false
cleanup_prepared_bundles ||
warn "Plugin rollback was successful, but previous release bundle state could not be fully restored."
else
error "Automatic rollback could not fully restore the previous plugin state. Manual intervention is required."
fi
else
cleanup_prepared_bundles ||
warn "Could not fully restore previous release bundle state."
fi
clean_up 1
}
# ----------
# Jobhandling
# ----------
trap 'handle_signal' SIGHUP SIGINT SIGTERM
if ! mkdir "$LOCK_DIR" 2>/dev/null ; then
echo "Cannot create lock directory '$LOCK_DIR'."
exit 1
fi
if [[ -t 1 ]] ; then
terminal=true
else
fatal "Script must run in a terminal."
fi
# ==========
# Begin Main Script
# ==========
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
blank_line
# ----------
# Some checks
# ----------
echononl "Check if script is running as root.."
if [[ "$(id -u)" -eq 0 ]]; then
echo_ok
else
echo_failed
fatal "This script must be run as root."
fi
for _cmd in git curl tar awk grep sed sort python3 systemctl stat uname mv cp mkdir ; do
echononl "Check for command '${_cmd}'.."
if command -v "$_cmd" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Required command '${_cmd}' was not found."
fi
done
echononl "Check Mattermost binary.."
if [[ -x "$MM_BIN" ]]; then
echo_ok
else
echo_failed
fatal "Mattermost binary '${MM_BIN}' was not found."
fi
echononl "Check mmctl binary.."
if [[ -x "$MMCTL" ]]; then
echo_ok
else
echo_failed
fatal "mmctl binary '${MMCTL}' was not found."
fi
echononl "Check Mattermost service '${MM_SERVICE}'.."
if systemctl is-active --quiet "$MM_SERVICE" ; then
echo_ok
else
echo_failed
fatal "Mattermost service '${MM_SERVICE}' is not active."
fi
echononl "Check Mattermost user '${MM_USER}'.."
if id "$MM_USER" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Mattermost user '${MM_USER}' does not exist."
fi
echononl "Check Mattermost group '${MM_GROUP}'.."
if getent group "$MM_GROUP" > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Mattermost group '${MM_GROUP}' does not exist."
fi
echononl "Check Mattermost configuration '${MM_CONFIG_FILE}'.."
if [[ -r "$MM_CONFIG_FILE" ]]; then
echo_ok
else
echo_failed
fatal "Mattermost configuration '${MM_CONFIG_FILE}' is not readable."
fi
echononl "Check Mattermost Local Mode configuration.."
_local_data="$(python3 - "$MM_CONFIG_FILE" <<'PY_EOF'
import json, sys
with open(sys.argv[1], encoding="utf-8") as f:
data = json.load(f)
s = data.get("ServiceSettings", {})
print("true" if s.get("EnableLocalMode") is True else "false")
print(s.get("LocalModeSocketLocation") or "/var/tmp/mattermost_local.socket")
PY_EOF
)" || {
echo_failed
fatal "Could not parse '${MM_CONFIG_FILE}'."
}
_local_enabled="$(printf '%s\n' "$_local_data" | sed -n '1p')"
_local_socket="$(printf '%s\n' "$_local_data" | sed -n '2p')"
if [[ "$_local_enabled" = "true" ]]; then
MM_LOCAL_SOCKET="$_local_socket"
echo_ok
else
echo_failed
fatal "Mattermost Local Mode is disabled. Set ServiceSettings.EnableLocalMode to true and restart Mattermost first."
fi
echononl "Check Mattermost Local Mode socket '${MM_LOCAL_SOCKET}'.."
if [[ -S "$MM_LOCAL_SOCKET" ]]; then
echo_ok
else
echo_failed
fatal "Mattermost Local Mode socket '${MM_LOCAL_SOCKET}' does not exist."
fi
echononl "Test mmctl Local Mode connection.."
if "$MMCTL" --local plugin list > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "mmctl Local Mode connection failed. $(cat "$log_file")"
fi
echononl "Check Mattermost plugin configuration.."
_plugin_settings="$(python3 - "$MM_CONFIG_FILE" <<'PY_EOF'
import json, sys
with open(sys.argv[1], encoding="utf-8") as f:
data = json.load(f)
s = data.get("PluginSettings", {})
print("true" if s.get("Enable") is True else "false")
print("true" if s.get("EnableUploads") is True else "false")
PY_EOF
)" || {
echo_failed
fatal "Could not parse Mattermost plugin settings in '${MM_CONFIG_FILE}'."
}
_plugins_enabled="$(printf '%s\n' "$_plugin_settings" | sed -n '1p')"
_plugin_uploads_enabled="$(printf '%s\n' "$_plugin_settings" | sed -n '2p')"
if [[ "$_plugins_enabled" != "true" ]]; then
echo_failed
fatal "Mattermost plugins are disabled. Set PluginSettings.Enable to true and restart Mattermost first."
elif [[ "$_plugin_uploads_enabled" != "true" ]]; then
echo_failed
fatal "Mattermost plugin uploads are disabled. Set PluginSettings.EnableUploads to true and restart Mattermost first."
else
echo_ok
fi
MM_SERVER_VERSION="$("$MM_BIN" version 2>/dev/null | awk -F': ' '$1 == "Version" {print $2; exit}')"
[[ -n "$MM_SERVER_VERSION" ]] || fatal "Could not determine installed Mattermost version."
# ----------
# Detect installation mode
# ----------
echononl "Detect existing Mattermost OIDC plugin installation.."
MM_CURRENT_VERSION="$(installed_plugin_version 2>/dev/null)"
_plugin_version_rc=$?
if [[ $_plugin_version_rc -eq 0 && -n "$MM_CURRENT_VERSION" ]]; then
INSTALLATION_MODE="upgrade"
plugin_is_enabled
_plugin_enabled_rc=$?
if [[ $_plugin_enabled_rc -eq 0 ]]; then
MM_PREVIOUS_PLUGIN_ENABLED=true
elif [[ $_plugin_enabled_rc -eq 2 ]]; then
MM_PREVIOUS_PLUGIN_ENABLED=false
else
echo_failed
fatal "Could not determine whether Mattermost OIDC Plugin '${MM_OIDC_PLUGIN_ID}' is enabled or disabled."
fi
echo_ok
elif [[ $_plugin_version_rc -eq 2 ]]; then
INSTALLATION_MODE="initial-installation"
MM_CURRENT_VERSION=""
echo_ok
else
echo_failed
fatal "Could not determine current Mattermost OIDC plugin state."
fi
# ----------
# Determine latest stable release
# ----------
echononl "Determine latest stable Mattermost OIDC release.."
MM_LATEST_VERSION="$(git ls-remote --tags --refs "$MM_OIDC_REPOSITORY" 2> "$log_file" \
| awk '{print $2}' \
| sed -nE 's#refs/tags/v([0-9]+\.[0-9]+\.[0-9]+)$#\1#p' \
| sort -V \
| tail -1)"
if [[ -n "$MM_LATEST_VERSION" ]]; then
echo_ok
else
echo_failed
fatal "Could not determine latest stable release from '${MM_OIDC_REPOSITORY}'. $(cat "$log_file")"
fi
blank_line
if [[ "$INSTALLATION_MODE" = "initial-installation" ]]; then
echo " Installation mode....................: Initial installation"
else
echo " Installation mode....................: Upgrade"
echo " Currently installed version.........: ${MM_CURRENT_VERSION}"
fi
echo " Installed Mattermost version........: ${MM_SERVER_VERSION}"
echo " Latest stable OIDC version..........: ${MM_LATEST_VERSION}"
blank_line
while true ; do
echononl "New Mattermost OIDC Plugin Version [${MM_LATEST_VERSION}]: "
read MM_NEW_VERSION
MM_NEW_VERSION="${MM_NEW_VERSION#v}"
[[ -z "$MM_NEW_VERSION" ]] && MM_NEW_VERSION="$MM_LATEST_VERSION"
echononl "Check release tag 'v${MM_NEW_VERSION}'.."
if git ls-remote --exit-code --tags "$MM_OIDC_REPOSITORY" \
"refs/tags/v${MM_NEW_VERSION}" "refs/tags/v${MM_NEW_VERSION}^{}" \
> /dev/null 2> "$log_file" ; then
echo_ok
break
else
echo_failed
warn "Tag 'v${MM_NEW_VERSION}' does not exist in the upstream repository."
fi
done
if [[ "$INSTALLATION_MODE" = "upgrade" && "$MM_NEW_VERSION" = "$MM_CURRENT_VERSION" ]]; then
blank_line
warn "Mattermost OIDC Plugin ${MM_CURRENT_VERSION} is already installed."
if ! ask_yes_no "Reinstall version ${MM_NEW_VERSION}" "no" ; then
info "Version ${MM_CURRENT_VERSION} is already installed. Nothing to do."
clean_up 0
fi
fi
MM_BUNDLE="${MM_SOURCE_BASE}/mattermost-oidc-${MM_NEW_VERSION}.tar.gz"
# ----------
# Summary
# ----------
blank_line
echo -e "\033[37m\033[1mMattermost OIDC Plugin installation settings:\033[m"
blank_line
echo " Installation mode....................: ${INSTALLATION_MODE}"
[[ -n "$MM_CURRENT_VERSION" ]] && echo " Current plugin version...............: ${MM_CURRENT_VERSION}"
echo " New plugin version...................: ${MM_NEW_VERSION}"
echo " Latest stable version...............: ${MM_LATEST_VERSION}"
echo " Installed Mattermost version........: ${MM_SERVER_VERSION}"
echo " Repository...........................: ${MM_OIDC_REPOSITORY}"
echo " Release bundle.......................: ${MM_BUNDLE}"
echo " Plugin ID............................: ${MM_OIDC_PLUGIN_ID}"
echo " Local Mode socket....................: ${MM_LOCAL_SOCKET}"
blank_line
if ! ask_yes_no "einverstanden" "no" ; then
fatal "Stopped by user"
fi
# ----------
# Prepare source directory
# ----------
blank_line
# ----------
# Download release bundle
# ----------
blank_line
echo -e "\033[37m\033[1mPrepare Mattermost OIDC Plugin release bundle..\033[m"
blank_line
echononl "Create source directory '${MM_SOURCE_BASE}'.."
if mkdir -p "$MM_SOURCE_BASE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
if [[ -e "$MM_BUNDLE" ]]; then
MM_BUNDLE_BACKUP="${MM_BUNDLE}.${backup_date}"
echononl "Backup existing release bundle.."
if mv "$MM_BUNDLE" "$MM_BUNDLE_BACKUP" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
fatal "$(cat "$log_file")"
fi
else
echononl "Backup existing release bundle.."
echo_skipped
fi
echononl "Download Mattermost OIDC Plugin ${MM_NEW_VERSION}.."
_release_url="${MM_OIDC_RELEASE_BASE}/v${MM_NEW_VERSION}/mattermost-oidc-${MM_NEW_VERSION}.tar.gz"
if curl -fL --retry 2 --connect-timeout 15 -o "$MM_BUNDLE" "$_release_url" > "$log_file" 2>&1 ; then
echo_ok
else
_download_error="$(cat "$log_file")"
echo_failed
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Could not download '${_release_url}'. ${_download_error}"
fi
echononl "Check release bundle archive.."
if tar tzf "$MM_BUNDLE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Downloaded release bundle is not a valid gzip-compressed tar archive."
fi
echononl "Read and verify plugin metadata.."
_plugin_json="$(tar xOf "$MM_BUNDLE" mattermost-oidc/plugin.json 2> "$log_file")" || {
echo_failed
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Could not read mattermost-oidc/plugin.json from release bundle."
}
_metadata="$(printf '%s' "$_plugin_json" | python3 -c '
import json, sys
expected_id, expected_version = sys.argv[1:3]
try:
data = json.load(sys.stdin)
except Exception:
raise SystemExit(1)
if data.get("id") != expected_id:
raise SystemExit(2)
if data.get("version") != expected_version:
raise SystemExit(3)
print(data.get("min_server_version", ""))
' "$MM_OIDC_PLUGIN_ID" "$MM_NEW_VERSION")"
_metadata_rc=$?
if [[ $_metadata_rc -eq 0 ]]; then
MM_MIN_SERVER_VERSION="$_metadata"
echo_ok
else
echo_failed
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Plugin metadata does not match expected ID '${MM_OIDC_PLUGIN_ID}' and version '${MM_NEW_VERSION}'."
fi
if [[ -n "$MM_MIN_SERVER_VERSION" ]]; then
echononl "Check Mattermost version (installed: ${MM_SERVER_VERSION}, required: ${MM_MIN_SERVER_VERSION}).."
if version_ge "$MM_SERVER_VERSION" "$MM_MIN_SERVER_VERSION" ; then
echo_ok
else
echo_failed
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Mattermost ${MM_NEW_VERSION} requires Mattermost ${MM_MIN_SERVER_VERSION} or newer. Installed version is ${MM_SERVER_VERSION}."
fi
fi
_arch="$(uname -m)"
case "$_arch" in
x86_64|amd64) _bundle_arch="amd64" ;;
aarch64|arm64) _bundle_arch="arm64" ;;
*)
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Unsupported system architecture '${_arch}'."
;;
esac
echononl "Check Linux server binary for architecture '${_bundle_arch}'.."
if tar tzf "$MM_BUNDLE" | grep -qx "mattermost-oidc/server/dist/plugin-linux-${_bundle_arch}" ; then
echo_ok
else
echo_failed
restore_release_bundle || warn "Could not restore previous release bundle."
fatal "Release bundle does not contain plugin-linux-${_bundle_arch}."
fi
# ----------
# Prepare rollback bundle
# ----------
if [[ "$INSTALLATION_MODE" = "upgrade" ]]; then
MM_ROLLBACK_BUNDLE="${MM_SOURCE_BASE}/mattermost-oidc-${MM_CURRENT_VERSION}.rollback-${backup_date}.tar.gz"
blank_line
echo -e "\033[37m\033[1mPrepare Mattermost OIDC Plugin rollback bundle..\033[m"
blank_line
echononl "Download rollback bundle for Mattermost OIDC Plugin ${MM_CURRENT_VERSION}.."
_rollback_url="${MM_OIDC_RELEASE_BASE}/v${MM_CURRENT_VERSION}/mattermost-oidc-${MM_CURRENT_VERSION}.tar.gz"
if curl -fL --retry 2 --connect-timeout 15 -o "$MM_ROLLBACK_BUNDLE" "$_rollback_url" > "$log_file" 2>&1 ; then
echo_ok
else
_rollback_download_error="$(cat "$log_file")"
echo_failed
cleanup_prepared_bundles || warn "Could not fully restore previous release bundle state."
fatal "Could not prepare rollback bundle '${_rollback_url}'. No changes were made to the installed plugin. ${_rollback_download_error}"
fi
echononl "Check rollback bundle archive.."
if tar tzf "$MM_ROLLBACK_BUNDLE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
cleanup_prepared_bundles || warn "Could not fully restore previous release bundle state."
fatal "Rollback bundle for version '${MM_CURRENT_VERSION}' is not a valid gzip-compressed tar archive."
fi
echononl "Verify rollback bundle metadata.."
_rollback_plugin_json="$(tar xOf "$MM_ROLLBACK_BUNDLE" mattermost-oidc/plugin.json 2> "$log_file")" || {
echo_failed
cleanup_prepared_bundles || warn "Could not fully restore previous release bundle state."
fatal "Could not read plugin metadata from rollback bundle."
}
if printf '%s' "$_rollback_plugin_json" | python3 -c '
import json, sys
expected_id, expected_version = sys.argv[1:3]
try:
data = json.load(sys.stdin)
except Exception:
raise SystemExit(1)
if data.get("id") != expected_id or data.get("version") != expected_version:
raise SystemExit(1)
' "$MM_OIDC_PLUGIN_ID" "$MM_CURRENT_VERSION" ; then
echo_ok
else
echo_failed
cleanup_prepared_bundles || warn "Could not fully restore previous release bundle state."
fatal "Rollback bundle metadata does not match plugin '${MM_OIDC_PLUGIN_ID}' version '${MM_CURRENT_VERSION}'."
fi
fi
# ----------
# Install/upgrade plugin
# ----------
blank_line
echo -e "\033[37m\033[1mInstall Mattermost OIDC Plugin..\033[m"
blank_line
echononl "Install Mattermost OIDC Plugin ${MM_NEW_VERSION}.."
MM_ROLLBACK_REQUIRED=true
if "$MMCTL" --local plugin add --force "$MM_BUNDLE" > "$log_file" 2>&1 ; then
echo_ok
else
_install_error="$(cat "$log_file")"
echo_failed
fatal_with_plugin_rollback "Plugin installation failed. ${_install_error}"
fi
echononl "Enable Mattermost OIDC Plugin '${MM_OIDC_PLUGIN_ID}'.."
if "$MMCTL" --local plugin enable "$MM_OIDC_PLUGIN_ID" > "$log_file" 2>&1 ; then
echo_ok
else
_enable_error="$(cat "$log_file")"
echo_failed
fatal_with_plugin_rollback "Plugin was installed but could not be enabled. ${_enable_error}"
fi
# ----------
# Verify installation
# ----------
blank_line
echo -e "\033[37m\033[1mVerify Mattermost OIDC Plugin installation..\033[m"
blank_line
sleep 1
echononl "Verify installed plugin version '${MM_NEW_VERSION}'.."
_verified_version="$(installed_plugin_version 2>/dev/null)"
if [[ "$_verified_version" = "$MM_NEW_VERSION" ]]; then
echo_ok
else
echo_failed
fatal_with_plugin_rollback "Installed plugin version is '${_verified_version:-unknown}', expected '${MM_NEW_VERSION}'."
fi
echononl "Verify plugin is enabled.."
plugin_is_enabled
_plugin_enabled_rc=$?
if [[ $_plugin_enabled_rc -eq 0 ]]; then
echo_ok
MM_ROLLBACK_REQUIRED=false
elif [[ $_plugin_enabled_rc -eq 2 ]]; then
echo_failed
fatal_with_plugin_rollback "Plugin '${MM_OIDC_PLUGIN_ID}' is installed but not enabled."
else
echo_failed
fatal_with_plugin_rollback "Could not determine whether Mattermost OIDC Plugin '${MM_OIDC_PLUGIN_ID}' is enabled."
fi
if [[ -n "$MM_ROLLBACK_BUNDLE" && -f "$MM_ROLLBACK_BUNDLE" ]]; then
echononl "Remove temporary rollback bundle.."
if rm -f "$MM_ROLLBACK_BUNDLE" > "$log_file" 2>&1 ; then
echo_ok
else
echo_failed
warn "Mattermost OIDC Plugin was successfully installed, but temporary rollback bundle '${MM_ROLLBACK_BUNDLE}' could not be removed."
fi
fi
if [[ -n "$MM_BUNDLE_BACKUP" && -f "$MM_BUNDLE_BACKUP" ]]; then
echononl "Remove previous release bundle backup.."
if rm -f "$MM_BUNDLE_BACKUP" > "$log_file" 2>&1 ; then
MM_BUNDLE_BACKUP=""
echo_ok
else
echo_failed
warn "Mattermost OIDC Plugin was successfully installed, but previous release bundle backup '${MM_BUNDLE_BACKUP}' could not be removed."
fi
fi
# ----------
# Final information
# ----------
blank_line
echo -e "\033[37m\033[1mMattermost OIDC Plugin successfully installed.\033[m"
blank_line
echo " Installed version.....................: ${MM_NEW_VERSION}"
echo " Plugin ID.............................: ${MM_OIDC_PLUGIN_ID}"
echo " Release bundle........................: ${MM_BUNDLE}"
echo " Mattermost version....................: ${MM_SERVER_VERSION}"
echo " Minimum Mattermost version............: ${MM_MIN_SERVER_VERSION:-not specified}"
echo " Status................................: enabled"
blank_line
clean_up 0
+1353
View File
File diff suppressed because it is too large Load Diff
+266 -60
View File
@@ -9,7 +9,7 @@ conf_file="${working_dir}/conf/mattermost.conf"
LOCK_DIR="/tmp/$(basename $0).$$.LOCK"
log_file="${LOCK_DIR}/${script_name%%.*}.log"
backup_date="$(date +%Y-%m-%d-%H%M)"
backup_date="$(date +%Y-%m-%d-%H%M%S)"
# ----------
@@ -64,8 +64,7 @@ fatal(){
echo -e " Script terminated.."
fi
echo ""
rm -rf $LOCK_DIR
exit 1
clean_up 1
}
error (){
echo ""
@@ -136,14 +135,14 @@ blank_line() {
detect_os () {
if $(which lsb_release > /dev/null 2>&1) ; then
if command -v 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
if echo "$DIST_VERSION" | grep -q '\.' ; then
DIST_VERSION=$(echo "$DIST_VERSION" | cut --delimiter='.' -f1)
fi
fi
@@ -171,7 +170,7 @@ detect_os () {
# - Run 'clean_up' for signals SIGHUP SIGINT SIGTERM
# -
trap clean_up SIGHUP SIGINT SIGTERM
trap 'clean_up 1' SIGHUP SIGINT SIGTERM
# - Create lock directory '$LOCK_DIR"
#
@@ -273,8 +272,9 @@ do
echo -e "\n\t\033[33m\033[1mA Version number is required!\033[m\n"
fi
done
DOWNLOAD_ARCHIVE="mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz"
DOWNLOAD_URL="https://releases.mattermost.com/${MM_NEW_VERSION}/${DOWNLOAD_ARCHIVE}"
# Download archive is selected after the current installation has been inspected.
DOWNLOAD_ARCHIVE=
DOWNLOAD_URL=
@@ -313,8 +313,93 @@ else
done
fi
MATTERMOST_CURRENT_VERSION="$(${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost version 2> /dev/null | grep -E "^Version:" | cut -d' ' -f2)"
MATTERMOST_CURRENT_BUILD_NUMBER="$(${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost version 2> /dev/null | grep -E "^Build Number:" | cut -d' ' -f3)"
if [[ ! -x "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost" ]]; then
fatal "Mattermost binary '${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost' does not exist or is not executable."
fi
if ! MATTERMOST_VERSION_OUTPUT="$("${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost" version 2> /dev/null)" ; then
fatal "Failed to determine the currently installed Mattermost version."
fi
MATTERMOST_CURRENT_VERSION="$(echo "$MATTERMOST_VERSION_OUTPUT" | grep -E "^Version:" | cut -d' ' -f2)"
MATTERMOST_CURRENT_BUILD_NUMBER="$(echo "$MATTERMOST_VERSION_OUTPUT" | grep -E "^Build Number:" | cut -d' ' -f3)"
MATTERMOST_CURRENT_ENTERPRISE_READY="$(echo "$MATTERMOST_VERSION_OUTPUT" | grep -E "^Build Enterprise Ready:" | awk '{print $4}')"
if [[ "${MATTERMOST_CURRENT_ENTERPRISE_READY,,}" = "true" ]]; then
MATTERMOST_CURRENT_EDITION="enterprise"
MATTERMOST_CURRENT_EDITION_NAME="Enterprise Ready"
elif [[ "${MATTERMOST_CURRENT_ENTERPRISE_READY,,}" = "false" ]]; then
MATTERMOST_CURRENT_EDITION="team"
MATTERMOST_CURRENT_EDITION_NAME="Team Edition"
else
MATTERMOST_CURRENT_EDITION="unknown"
MATTERMOST_CURRENT_EDITION_NAME="Unknown"
fi
echo -e "\033[32m--\033[m"
echo ""
echo "Choose Mattermost Edition for the upgrade"
echo ""
if [[ "$MATTERMOST_CURRENT_EDITION" = "enterprise" ]]; then
echo -e "\033[3G\033[37m\033[1m[1] Enterprise Ready\033[m"
echo -e "\033[3G[2] Team Edition"
elif [[ "$MATTERMOST_CURRENT_EDITION" = "team" ]]; then
echo -e "\033[3G[1] Enterprise Ready"
echo -e "\033[3G\033[37m\033[1m[2] Team Edition\033[m"
else
echo -e "\033[3G[1] Enterprise Ready"
echo -e "\033[3G[2] Team Edition"
fi
echo ""
echo "Current edition: ${MATTERMOST_CURRENT_EDITION_NAME}"
echo ""
if [[ "$MATTERMOST_CURRENT_EDITION" != "unknown" ]]; then
echo "Press <RETURN> to keep the current edition"
echo ""
fi
echononl "Eingabe: "
MATTERMOST_EDITION=
while [[ "$MATTERMOST_EDITION" != "enterprise" ]] && [[ "$MATTERMOST_EDITION" != "team" ]]; do
read OPTION
case $OPTION in
1)
MATTERMOST_EDITION="enterprise"
MATTERMOST_EDITION_NAME="Enterprise Ready"
DOWNLOAD_ARCHIVE="mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz"
;;
2)
MATTERMOST_EDITION="team"
MATTERMOST_EDITION_NAME="Team Edition"
DOWNLOAD_ARCHIVE="mattermost-team-${MM_NEW_VERSION}-linux-amd64.tar.gz"
;;
'')
if [[ "$MATTERMOST_CURRENT_EDITION" = "team" ]]; then
MATTERMOST_EDITION="team"
MATTERMOST_EDITION_NAME="Team Edition"
DOWNLOAD_ARCHIVE="mattermost-team-${MM_NEW_VERSION}-linux-amd64.tar.gz"
elif [[ "$MATTERMOST_CURRENT_EDITION" = "enterprise" ]]; then
MATTERMOST_EDITION="enterprise"
MATTERMOST_EDITION_NAME="Enterprise Ready"
DOWNLOAD_ARCHIVE="mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz"
else
echo ""
echo -e "\033[3GNo default edition available. Please choose 1 or 2."
echo ""
echononl "Eingabe: "
fi
;;
*)
echo ""
echo -e "\033[3GWrong entry! [ 1 = Enterprise Ready ; 2 = Team Edition ]"
echo ""
echononl "Eingabe: "
;;
esac
done
DOWNLOAD_URL="https://releases.mattermost.com/${MM_NEW_VERSION}/${DOWNLOAD_ARCHIVE}"
if [[ "$MATTERMOST_CURRENT_EDITION" != "unknown" ]] && [[ "$MATTERMOST_CURRENT_EDITION" != "$MATTERMOST_EDITION" ]]; then
warn "You are changing the Mattermost edition from '${MATTERMOST_CURRENT_EDITION_NAME}' to '${MATTERMOST_EDITION_NAME}'."
fi
@@ -412,7 +497,7 @@ done
if [[ "$DB_TYPE" = "mysql" ]] ; then
if [[ -n "$MYSQL_CREDENTIAL_ARGS" ]] ; then
if ! $(mysql $MYSQL_CREDENTIAL_ARGS -N -s -e 'quit' > /dev/null 2>&1) ; then
if ! mysql $MYSQL_CREDENTIAL_ARGS -N -s -e 'quit' > /dev/null 2>&1 ; then
fatal "Parameter MYSQL_CREDENTIAL_ARGS is given, but a connection to MySQL Service failed.!"
fi
USE_MYSQL_CREDENTIAL_ARGS=true
@@ -433,8 +518,8 @@ if [[ "$DB_TYPE" = "mysql" ]] ; then
echo -e "\n\t\033[33m\033[1mPassworteingabe erforderlich!\033[m\n"
continue
fi
if $(pgrep mysqld_safe > /dev/null 2>&1) || $(pgrep mysqld > /dev/null 2>&1); then
if $(mysql --user="root" --password="$_MYSQL_ROOT_PW" -N -s -e 'quit' > /dev/null 2>&1) ; then
if pgrep mysqld_safe > /dev/null 2>&1 || pgrep mysqld > /dev/null 2>&1; then
if mysql --user="root" --password="$_MYSQL_ROOT_PW" -N -s -e 'quit' > /dev/null 2>&1 ; then
MYSQL_ROOT_PW=$_MYSQL_ROOT_PW
else
echo -e "\n\t\033[33m\033[1mFalsches Passwort\033[m\n"
@@ -455,8 +540,10 @@ echo -e "\033[32mStart upgrade script for Mattermost Server with the following p
echo ""
echo -e " Mattermost current Server Version.: $MATTERMOST_CURRENT_VERSION"
echo -e " Mattermost current Build Number...: $MATTERMOST_CURRENT_BUILD_NUMBER"
echo -e " Mattermost current Edition........: $MATTERMOST_CURRENT_EDITION_NAME"
echo ""
echo -e " Mattermost New Server Version.....: \033[33m\033[1m$MM_NEW_VERSION\033[m"
echo -e " Mattermost New Edition............: \033[33m\033[1m$MATTERMOST_EDITION_NAME\033[m"
echo ""
echo -e " Full qualified Hostname...........: $FQHN_HOSTNAME"
echo -e " Hostname..........................: $HOSTNAME"
@@ -477,7 +564,7 @@ fi
echo ""
if [[ "${DB_TYPE}" = "mysql" ]]; then
if $USE_MYSQL_CREDENTIAL_ARGS ; then
echo -e " MYSQL_CREDENTIAL_ARGS.............: $MYSQL_CREDENTIAL_ARGS"
echo -e " MYSQL_CREDENTIAL_ARGS.............: **"
else
echo -e " Root password MySQL...............: **"
fi
@@ -485,7 +572,7 @@ fi
echo ""
echo -e " Database Name.....................: $DB_NAME"
echo -e " Database User.....................: $DB_USER"
echo -e " Database Password.................: $DB_PASS"
echo -e " Database Password.................: **"
echo ""
echononl "einverstanden (yes/no): "
read OK
@@ -501,9 +588,9 @@ done
blank_line
blank_line
if ! $USE_MYSQL_CREDENTIAL_ARGS ; then
MYSQL_CREDENTIAL_ARGS="--user='root' --password=$_MYSQL_ROOT_PW"
if ! $(mysql $MYSQL_CREDENTIAL_ARGS -N -s -e 'quit' > /dev/null 2>&1) ; then
if [[ "$DB_TYPE" = "mysql" ]] && ! $USE_MYSQL_CREDENTIAL_ARGS ; then
MYSQL_CREDENTIAL_ARGS="--user=root --password=$_MYSQL_ROOT_PW"
if ! mysql $MYSQL_CREDENTIAL_ARGS -N -s -e 'quit' > /dev/null 2>&1 ; then
fatal "Parameter MYSQL_CREDENTIAL_ARGS is given, but a connection to MySQL Service failed.!"
fi
fi
@@ -514,7 +601,7 @@ echo -e "\033[37m\033[1mSome pre-installation stuff..\033[m"
blank_line
echononl "Download version \033[1m${MM_NEW_VERSION}\033[m of the Mattermost Server.."
if [[ ! -f "${working_dir}/mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz" ]]; then
if [[ ! -f "${working_dir}/${DOWNLOAD_ARCHIVE}" ]]; then
wget -P ${working_dir} $DOWNLOAD_URL > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
@@ -536,6 +623,17 @@ else
echo_skipped
fi
echononl "Check Mattermost Server archive.."
if [[ -f "${working_dir}/${DOWNLOAD_ARCHIVE}" ]] \
&& tar -tzf "${working_dir}/${DOWNLOAD_ARCHIVE}" > /dev/null 2> "$log_file" ; then
echo_ok
else
echo_failed
fatal "Mattermost Server archive '${working_dir}/${DOWNLOAD_ARCHIVE}' is missing, invalid or incomplete."
fi
blank_line
# - Deaktiviere Cronjobs
# -
@@ -559,42 +657,35 @@ else
fi
echononl "Remove existing temporary Mattermost upgrade directory.."
if [[ -d "${MATTERMOST_TMP_DIR}/mattermost-upgrade" ]]; then
rm -rf "${MATTERMOST_TMP_DIR}/mattermost-upgrade" > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
fatal "$(cat "$log_file")"
else
echo_ok
fi
else
echo_skipped
fi
echononl "Extract the Mattermost Server files into TMP directory.."
tar -xf ${working_dir}/mattermost-${MM_NEW_VERSION}-linux-amd64.tar.gz \
-C ${MATTERMOST_TMP_DIR} --transform='s,^[^/]\+,\0-upgrade,'
tar -xf "${working_dir}/${DOWNLOAD_ARCHIVE}" \
-C "${MATTERMOST_TMP_DIR}" --transform='s,^[^/]\+,\0-upgrade,' > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
fatal "$(cat "$log_file")"
else
echo_ok
fi
echononl "Stop Mattermost Service.."
if $(systemctl is-active --quiet service mattermost.service) ; then
if systemctl is-active --quiet mattermost.service ; then
systemctl stop mattermost.service > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
echononl "continue anyway [yes/no]: "
read OK
OK="$(echo "$OK" | tr '[:upper:]' '[:lower:]')"
while [[ "$OK" != "yes" ]] && [[ "$OK" != "no" ]] ; do
echononl "Wrong entry! - repeat [yes/no]: "
read OK
done
[[ $OK = "yes" ]] || fatal "Stopped by user"
fatal "$(cat "$log_file")"
else
echo_ok
fi
@@ -604,8 +695,8 @@ fi
echononl "Backup mattermost database.."
if [[ "${DB_TYPE}" = "mysql" ]]; then
mysqldump --login-path=local --opt $DB_NAME \
> ${MATTERMOST_BASE_INSTALL_PATH}/${DB_NAME}-${backup_date}.sql 2> $log_file
mysqldump $MYSQL_CREDENTIAL_ARGS --opt "$DB_NAME" \
> "${MATTERMOST_BASE_INSTALL_PATH}/${DB_NAME}-${backup_date}.sql" 2> "$log_file"
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -641,8 +732,8 @@ else
fi
echononl "Backup mattermost installation directory.."
cp -ra ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/ \
${MATTERMOST_BASE_INSTALL_PATH}/mattermost-back-${backup_date}/ > "$log_file" 2>&1
cp -ra "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/" \
"${MATTERMOST_BASE_INSTALL_PATH}/mattermost-back-${backup_date}/" > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -660,20 +751,89 @@ else
fi
# - When switching from Enterprise Ready to Team Edition, remove stale
# - Enterprise-only plugin state before installing the Team Edition files.
# - Keep Playbooks explicitly disabled so AutomaticPrepackagedPlugins does
# - not try to install/activate it again on Team Edition startup.
#
if [[ "$MATTERMOST_CURRENT_EDITION" = "enterprise" ]] && [[ "$MATTERMOST_EDITION" = "team" ]]; then
blank_line
echo -e "\033[37m\033[1mPrepare Enterprise Ready -> Team Edition switch..\033[m"
blank_line
echononl "Check for Python 3 (needed to adjust Mattermost plugin configuration).."
if command -v python3 > /dev/null 2>&1 ; then
echo_ok
else
echo_failed
fatal "Python 3 is required for a safe Enterprise Ready -> Team Edition switch."
fi
echononl "Clean Enterprise-only plugin configuration for Team Edition.."
MM_CONFIG_FILE="${MATTERMOST_BASE_INSTALL_PATH}/mattermost/config/config.json"
python3 - "$MM_CONFIG_FILE" > "$log_file" 2>&1 <<'PY'
import json
import sys
path = sys.argv[1]
with open(path, "r", encoding="utf-8") as f:
data = json.load(f)
plugin_settings = data.setdefault("PluginSettings", {})
plugins = plugin_settings.setdefault("Plugins", {})
states = plugin_settings.setdefault("PluginStates", {})
plugins.pop("playbooks", None)
states.pop("com.mattermost.nps", None)
states["playbooks"] = {"Enable": False}
with open(path, "w", encoding="utf-8") as f:
json.dump(data, f, indent=4)
f.write("\n")
PY
if [[ $? -ne 0 ]]; then
echo_failed
fatal "Failed to adjust plugin configuration:\n$(cat "$log_file")"
else
echo_ok
fi
echononl "Remove installed Playbooks/NPS plugin files.."
rm -rf \
"${MATTERMOST_BASE_INSTALL_PATH}/mattermost/plugins/playbooks" \
"${MATTERMOST_BASE_INSTALL_PATH}/mattermost/plugins/com.mattermost.nps" \
"${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/plugins/playbooks" \
"${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/plugins/com.mattermost.nps" \
> "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
fatal "Failed to remove Enterprise-only plugin files:\n$(cat "$log_file")"
else
echo_ok
fi
fi
echo
echo -e "\033[37m\033[1mUpgrade Mattermost to version $MM_NEW_VERSION ..\033[m"
echo
echononl "Remove all files except \e[3mspecial directories\e[0m from within the current mattermost directory."
find ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/ ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/ \
-mindepth 1 -maxdepth 1 \! \( -type d \( -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/plugins \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/config \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/logs \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/plugins \
-o -path ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/data \) -prune \) | sort | sudo xargs rm -r > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
set -o pipefail
find "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/" "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/" \
-mindepth 1 -maxdepth 1 \! \( -type d \( -path "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client" \
-o -path "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/client/plugins" \
-o -path "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/config" \
-o -path "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/logs" \
-o -path "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/plugins" \
-o -path "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/data" \) -prune \) -print0 \
| sort -z | xargs -0 -r rm -r > "$log_file" 2>&1
_pipe_status=$?
set +o pipefail
if [[ $_pipe_status -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -692,7 +852,7 @@ fi
echononl "Change ownership of the new files before copying them.."
chown -hR ${MATTERMOST_USER}:${MATTERMOST_GROUP} ${MATTERMOST_TMP_DIR}/mattermost-upgrade/ > "$log_file" 2>&1
chown -hR "${MATTERMOST_USER}:${MATTERMOST_GROUP}" "${MATTERMOST_TMP_DIR}/mattermost-upgrade/" > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -712,7 +872,7 @@ fi
echononl "Copy the new files to your install directory.."
cp -an ${MATTERMOST_TMP_DIR}/mattermost-upgrade/. ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/ > "$log_file" 2>&1
cp -an "${MATTERMOST_TMP_DIR}/mattermost-upgrade/." "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/" > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -734,7 +894,7 @@ fi
# to bind to low ports.
#
echononl "Allow the new Mattermost binary to bind to low ports.."
setcap cap_net_bind_service=+ep ${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost > "$log_file" 2>&1
setcap cap_net_bind_service=+ep "${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost" > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -752,12 +912,46 @@ else
echo_ok
fi
echononl "Verify installed Mattermost binary.."
if ! INSTALLED_MATTERMOST_VERSION_OUTPUT="$("${MATTERMOST_BASE_INSTALL_PATH}/mattermost/bin/mattermost" version 2>&1)" ; then
echo_failed
fatal "Failed to determine the installed Mattermost version."
else
echo_ok
fi
echononl "Verify Mattermost Version.."
INSTALLED_MATTERMOST_VERSION="$(echo "$INSTALLED_MATTERMOST_VERSION_OUTPUT" | awk '/^Version:/ {print $2}')"
if [[ "$INSTALLED_MATTERMOST_VERSION" = "$MM_NEW_VERSION" ]]; then
echo_ok
else
echo_failed
fatal "Installed Mattermost version '${INSTALLED_MATTERMOST_VERSION}' does not match expected version '${MM_NEW_VERSION}'."
fi
echononl "Verify Mattermost Edition.."
if [[ "$MATTERMOST_EDITION" == "enterprise" ]]; then
if echo "$INSTALLED_MATTERMOST_VERSION_OUTPUT" | grep -q "Build Enterprise Ready: true"; then
echo_ok
else
echo_failed
fatal "Installed Mattermost binary is not Enterprise Ready."
fi
else
if echo "$INSTALLED_MATTERMOST_VERSION_OUTPUT" | grep -q "Build Enterprise Ready: false"; then
echo_ok
else
echo_failed
fatal "Installed Mattermost binary is not Team Edition."
fi
fi
blank_line
echo -e "\033[37m\033[1mSome post-installation stuff..\033[m"
blank_line
echononl "Remove the temporary files.."
rm -r ${MATTERMOST_TMP_DIR}/mattermost-upgrade/ > "$log_file" 2>&1
rm -r "${MATTERMOST_TMP_DIR}/mattermost-upgrade/" > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
@@ -780,9 +974,21 @@ systemctl start mattermost.service > "$log_file" 2>&1
if [[ $? -ne 0 ]]; then
echo_failed
error "$(cat "$log_file")"
clean_up 1
else
echo_ok
fi
echononl "Check Mattermost Service.."
sleep 3
if systemctl is-active --quiet mattermost.service ; then
echo_ok
else
echo_failed
systemctl status mattermost.service --no-pager >> "$log_file" 2>&1
error "$(cat "$log_file")"
clean_up 1
fi
clean_up 0