#!/bin/bash # # ***** BEGIN LICENSE BLOCK ***** # Zimbra Collaboration Suite Server # Copyright (C) 2024 Synacor, Inc. # # This program is free software: you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software Foundation, # version 2 of the License. # # This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; # without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. # See the GNU General Public License for more details. # You should have received a copy of the GNU General Public License along with this program. # If not, see . # ***** END LICENSE BLOCK ***** # ID=`id -u` if [ "x$ID" != "x0" ]; then echo "Run as root!" exit 1 fi if [ ! -f "/opt/zimbra/bin/zmcontrol" ] || [ ! -f "/opt/zimbra/conf/localconfig.xml" ]; then echo "The Zimbra Collaboration Server does not appear to be installed." exit 1 fi if [ ! -f "/opt/zimbra/bin/zmbackupquery" ]; then echo "Onlyoffice installation requires ZCS Network Edition." exit 1 fi PACKAGES="zimbra-onlyoffice zimbra-rabbitmq-server" LOGFILE=`mktemp -t onlyoffice-install.log.XXXXXXXX 2> /dev/null` || { echo "Failed to create tmpfile"; exit 1; } if [ -e "/tmp/onlyoffice-install.log" ]; then rm "/tmp/onlyoffice-install.log" fi ln -sf "$LOGFILE" "/tmp/onlyoffice-install.log" echo "Operations logged to $LOGFILE" getPlatformVars() { PLATFORM=`/opt/zimbra/libexec/get_plat_tag.sh` echo $PLATFORM | egrep -q "UBUNTU|DEBIAN" if [ $? = 0 ]; then REPOINST='apt-get install -y' PACKAGEDOWNLOAD='apt-get --download-only install -y --force-yes' PACKAGEQUERY='dpkg -s' PACKAGEEXT='deb' else REPOINST='yum -y install' PACKAGEDOWNLOAD='yum -y install --downloadonly' PACKAGEQUERY='rpm -q' PACKAGEEXT='rpm' fi } isInstalled() { pkg=$1 PKGINSTALLED="" if [ "x$PACKAGEEXT" = "xrpm" ]; then $PACKAGEQUERY $pkg >/dev/null 2>&1 if [ $? = 0 ]; then PKGVERSION=`$PACKAGEQUERY $pkg 2> /dev/null | sort -u` PKGINSTALLED=`$PACKAGEQUERY $pkg | sed -e 's/\.[a-zA-Z].*$//' 2> /dev/null` fi else Q=`$PACKAGEQUERY $pkg 2>/dev/null | egrep '^Status: ' ` if [ "x$Q" != "x" ]; then echo $Q | grep 'not-installed' > /dev/null 2>&1 if [ $? != 0 ]; then echo $Q | grep 'deinstall ok' > /dev/null 2>&1 if [ $? != 0 ]; then PKGVERSION=`$PACKAGEQUERY $pkg | egrep '^Version: ' | sed -e 's/Version: //' 2> /dev/null` PKGINSTALLED="${pkg}-${PKGVERSION}" fi fi fi fi } checkVersion() { isInstalled zimbra-core if [ x"$PKGINSTALLED" != "x" ]; then export ZMVERSION_CURRENT=`echo $PKGVERSION | sed s/^zimbra-core-//` ZM_CUR_MAJOR=$(perl -e '$v=$ENV{ZMVERSION_CURRENT}; $v =~ s/^(\d+\.\d+\.[^_]*_[^_]+_[^.]+).*/\1/; ($maj,$min,$mic) = $v =~ m/^(\d+)\.(\d+)\.(\d+)/; print "$maj\n"') ZM_CUR_MINOR=$(perl -e '$v=$ENV{ZMVERSION_CURRENT}; $v =~ s/^(\d+\.\d+\.[^_]*_[^_]+_[^.]+).*/\1/; ($maj,$min,$mic) = $v =~ m/^(\d+)\.(\d+)\.(\d+)/; print "$min\n"') ZM_CUR_MICRO=$(perl -e '$v=$ENV{ZMVERSION_CURRENT}; $v =~ s/^(\d+\.\d+\.[^_]*_[^_]+_[^.]+).*/\1/; ($maj,$min,$mic) = $v =~ m/^(\d+)\.(\d+)\.(\d+)/; print "$mic\n"') if [ ${ZM_CUR_MAJOR} -lt 10 ]; then echo "ERROR: zimbra-onlyoffice installation requires ZCS 10.0 or later." exit 1 fi fi } ask() { PROMPT=$1 DEFAULT=$2 echo "" echo -n "$PROMPT [$DEFAULT] " read response if [ -z $response ]; then response=$DEFAULT fi } askYN() { PROMPT=$1 DEFAULT=$2 if [ "x$DEFAULT" = "xyes" -o "x$DEFAULT" = "xYes" -o "x$DEFAULT" = "xy" -o "x$DEFAULT" = "xY" ]; then DEFAULT="Y" else DEFAULT="N" fi while [ 1 ]; do ask "$PROMPT" "$DEFAULT" response=$(perl -e "print lc(\"$response\");") if [ -z $response ]; then : else if [ $response = "yes" -o $response = "y" ]; then response="yes" break else if [ $response = "no" -o $response = "n" ]; then response="no" break fi fi fi echo "A Yes/No answer is required" done } configurePackageServer() { echo -e "" response="no" HOSTNAME=`hostname --fqdn` askYN "Use Zimbra's package repository" "Y" if [ $response = "yes" ]; then PACKAGE_SERVER="repo.zimbra.com" response="no" echo $HOSTNAME | egrep -qe 'eng.zimbra.com$|zimbradev.com$' > /dev/null 2>&1 if [ $? = 0 ]; then askYN "Use internal development repo" "N" if [ $response = "yes" ]; then PACKAGE_SERVER="repo-dev.eng.zimbra.com" else response="no" askYN "Use internal production mirror" "N" if [ $response = "yes" ]; then PACKAGE_SERVER="repo.eng.zimbra.com" fi fi fi fi echo $PLATFORM | egrep -q "UBUNTU|DEBIAN" if [ $? = 0 ]; then if [ $PLATFORM = "UBUNTU22_64" ]; then repo="jammy" elif [ $PLATFORM = "UBUNTU20_64" ]; then repo="focal" elif [ $PLATFORM = "UBUNTU18_64" ]; then repo="bionic" else print "Aborting, unknown platform: $PLATFORM" exit 1 fi echo "Configuring package repository" apt-get install -y apt-transport-https >>$LOGFILE 2>&1 if [ $? -ne 0 ]; then echo "ERROR: Unable to install packages via apt-get" echo "Please fix system to allow normal package installation before proceeding" exit 1 fi if [ ${ZM_CUR_MAJOR} -eq 10 -a ${ZM_CUR_MINOR} -eq 0 ]; then cat > /etc/apt/sources.list.d/zimbra-onlyoffice.list << EOF deb [arch=amd64] https://$PACKAGE_SERVER/apt/onlyoffice $repo zimbra EOF else cat > /etc/apt/sources.list.d/zimbra-onlyoffice.list << EOF deb [arch=amd64] https://$PACKAGE_SERVER/apt/onlyoffice-${ZM_CUR_MAJOR}${ZM_CUR_MINOR}${ZM_CUR_MICRO} $repo zimbra EOF fi apt-get update >>$LOGFILE 2>&1 if [ $? -ne 0 ]; then echo "ERROR: Unable to install packages via apt-get" echo "Please fix system to allow normal package installation before proceeding" exit 1 fi else if [ $PLATFORM = "RHEL7_64" ]; then repo="rhel7" elif [ $PLATFORM = "RHEL8_64" ]; then repo="rhel8" elif [ $PLATFORM = "RHEL9_64" ]; then repo="rhel9" else print "Aborting, unknown platform: $PLATFORM" exit 1 fi echo "Configuring package repository" if [ ${ZM_CUR_MAJOR} -eq 10 -a ${ZM_CUR_MINOR} -eq 0 ]; then cat > /etc/yum.repos.d/zimbra-onlyoffice.repo < /etc/yum.repos.d/zimbra-onlyoffice.repo <>$LOGFILE 2>&1 yum check-update --disablerepo=* --enablerepo=zimbra-onlyoffice --noplugins >>$LOGFILE 2>&1 if [ $? -ne 0 -a $? -ne 100 ]; then echo "ERROR: yum check-update failed" echo "Please validate ability to install packages" exit 1 fi fi } getInstallPackages() { INSTALL_PACKAGES="" isInstalled zimbra-store if [ "x$PKGINSTALLED" != "x" ]; then INSTALL_PACKAGES="$PACKAGES" else INSTALL_PACKAGES="$PACKAGES zimbra-mariadb" fi } pkgError() { echo "" echo "ERROR: Unable to install required packages" echo "Fix the issues with remote package installation and rerun the installer" exit 1 } installPackages() { echo echo "Beginning Installation - see $LOGFILE for details..." echo pretty_display() { local banner=$1; shift; local pk=("$@"); echo echo "$banner (${#pk[*]}):" | tee -a $LOGFILE local p; for p in "${pk[@]}" do echo " $(basename $p)" | tee -a $LOGFILE done echo -n " ..."; echo >> $LOGFILE } local repo_pkg_names=() for PKG in $INSTALL_PACKAGES do repo_pkg_names+=( "$PKG" ) done if [ "${#repo_pkg_names[@]}" -gt 0 ]; then pretty_display "Downloading packages" "${repo_pkg_names[@]}"; $PACKAGEDOWNLOAD "${repo_pkg_names[@]}" >> $LOGFILE 2>&1 if [ $? -ne 0 ]; then echo "Unable to download packages from repository. System is not modified." exit 1 fi echo "done" pretty_display "Installing repo packages" "${repo_pkg_names[@]}"; $REPOINST "${repo_pkg_names[@]}" >>$LOGFILE 2>&1 if [ $? != 0 ]; then pkgError fi echo "done" echo "Running Post Installation Configuration..." fi } runAsZimbra() { echo "COMMAND: $1" >> $LOGFILE 2>&1 su - zimbra -c "$1" >> $LOGFILE 2>&1 } isEnabled() { local service_name="$1" runAsZimbra "/opt/zimbra/bin/zmprov -l gs `/opt/zimbra/bin/zmhostname` zimbraServiceEnabled 2>/dev/null | grep -qw '$service_name'" if [ $? -eq 0 ]; then return 0 else return 1 fi } enableOnlyofficeService() { if ! isEnabled "onlyoffice"; then echo -n "Enabling Onlyoffice service... " if runAsZimbra "zmprov ms `/opt/zimbra/bin/zmhostname` +zimbraServiceInstalled onlyoffice +zimbraServiceEnabled onlyoffice"; then echo "done" else echo "failed" exit 1 fi fi } createSudoersFileIfNeeded() { if [ ! -e "/etc/sudoers.d/02_zimbra-store" ]; then echo "%zimbra ALL=NOPASSWD:/opt/zimbra/libexec/zmmailboxdmgr" | sudo tee /etc/sudoers.d/02_zimbra-store >/dev/null sudo chmod 440 /etc/sudoers.d/02_zimbra-store fi } initSql() { if [ ! -f "/opt/zimbra/log/zmmyinit.log" ] || [ ! -d "/opt/zimbra/db/data/zimbra" ]; then if isEnabled "onlyoffice"; then echo -n "Initializing sql database..." runAsZimbra "zmlocalconfig -e mysql_bind_address=127.0.0.1" runAsZimbra "/opt/zimbra/libexec/zmmyinit" echo "done" fi fi } createOnlyofficeDB() { mysql_root_pass=$(su - zimbra -c "zmlocalconfig -x -s -m nokey mysql_root_password") runAsZimbra '/opt/zimbra/bin/mysql -e "USE onlyoffice;"' if [ $? -ne 0 ]; then echo -n "Creating onlyoffice database..." runAsZimbra "/opt/zimbra/common/bin/mysql -S /opt/zimbra/data/tmp/mysql/mysql.sock -u root --password=$mysql_root_pass < /opt/zimbra/onlyoffice/bin/createdb.sql" if [ $? = 0 ]; then echo "done" else echo "failed" exit 1 fi fi } createDirForOnlyoffice() { local zimbra_user="zimbra" local zimbra_uid=$(id -u "$zimbra_user") local zimbra_gid=$(id -g "$zimbra_user") local dir_to_create=( '/opt/zimbra/index' '/opt/zimbra/store' '/opt/zimbra/data/tmp/mysql' '/opt/zimbra/mailboxd' '/opt/zimbra/common/conf' ) for dir in "${dir_to_create[@]}"; do if [ ! -d "$dir" ]; then mkdir -p "$dir" chown "$zimbra_uid:$zimbra_gid" "$dir" chmod 0755 "$dir" fi done } configureOnlyoffice() { if isEnabled "onlyoffice"; then echo -n "Configuring Onlyoffice..." runAsZimbra "/opt/zimbra/bin/zmprov -r -m -l mc default zimbraFeatureViewInHTMLEnabled TRUE" chmod +x /opt/zimbra/onlyoffice/bin/zmonlyofficeconfig /opt/zimbra/onlyoffice/bin/zmonlyofficeconfig chmod 775 /opt/zimbra/onlyoffice/bin/process_id.json chown -R zimbra:zimbra /opt/zimbra/onlyoffice/ createOnlyofficeDB if isEnabled "mailbox"; then ONLYOFFICESTANDALONE="no" else ONLYOFFICESTANDALONE="yes" fi # set the config value zimbraDocumentServerHost # if not standalone: # set the server host name at server level config # if standalone server : # 1. global config already present, do not override # 2. global config not present, this server name goes as global config if [ "$ONLYOFFICESTANDALONE" = "no" ]; then runAsZimbra "/opt/zimbra/bin/zmprov -r -m -l ms `/opt/zimbra/bin/zmhostname` zimbraDocumentServerHost `/opt/zimbra/bin/zmhostname`" else ONLYOFFICE_HOST=$(su - zimbra -c "zmprov -l gacf zimbraDocumentServerHost" | awk -F': ' '/zimbraDocumentServerHost/{print $2}') if [ -z "$ONLYOFFICE_HOST" ]; then runAsZimbra "/opt/zimbra/bin/zmprov -r -m -l mcf zimbraDocumentServerHost `/opt/zimbra/bin/zmhostname`" fi fi fi } startServices() { echo -n "Starting Services..." if isEnabled "onlyoffice"; then if ! su - zimbra -c "/opt/zimbra/bin/zmonlyofficectl restart &>/dev/null"; then echo "failed to start onlyoffice" fi fi if isEnabled "proxy"; then if ! su - zimbra -c "/opt/zimbra/bin/zmproxyctl restart &>/dev/null"; then echo "failed to restart proxy service" fi else echo "restart proxy service as zimbra user" fi if ! su - zimbra -c "/opt/zimbra/bin/zmconfigdctl restart &>/dev/null"; then echo "failed to restart zmconfigdctl" fi echo "done" echo "Configuration complete." } getPlatformVars checkVersion configurePackageServer getInstallPackages installPackages enableOnlyofficeService createDirForOnlyoffice createSudoersFileIfNeeded initSql configureOnlyoffice startServices