#!/usr/bin/env bash set -e usage() { cat <&2 exit 1 fi ## Options from environment variables. # # Specify options for apt. read -r -a APT_OPTIONS <<< "${APT_OPTIONS:-}" # Install additional packages. read -r -a ADDITIONAL_PACKAGES <<< "${ADDITIONAL_PACKAGES:-}" # Deployment type is almost always voyager. DEPLOYMENT_TYPE="${DEPLOYMENT_TYPE:-voyager}" # Comma-separated list of puppet manifests to install. default is # zulip::voyager for an all-in-one system or zulip::dockervoyager for # Docker. Use e.g. zulip::app_frontend for a Zulip frontend server. PUPPET_CLASSES="${PUPPET_CLASSES:-zulip::voyager}" VIRTUALENV_NEEDED="${VIRTUALENV_NEEDED:-yes}" if [ -n "$SELF_SIGNED_CERT" ] && [ -n "$USE_CERTBOT" ]; then set +x echo "error: --self-signed-cert and --certbot are incompatible" >&2 echo >&2 usage >&2 exit 1 fi if [ -z "$EXTERNAL_HOST" ] || [ -z "$ZULIP_ADMINISTRATOR" ]; then if [ -n "$USE_CERTBOT" ] || [ -z "$NO_INIT_DB" ]; then usage >&2 exit 1 fi fi if [ "$EXTERNAL_HOST" = zulip.example.com ] || [ "$ZULIP_ADMINISTRATOR" = zulip-admin@example.com ]; then # These example values are specifically checked for and would fail # later; see check_config in zerver/lib/management.py. echo 'error: The example hostname and email must be replaced with real values.' >&2 echo >&2 usage >&2 exit 1 fi # Do set -x after option parsing is complete set -x ZULIP_PATH="$(readlink -f "$(dirname "$0")"/../..)" # Force a known locale. Some packages on PyPI fail to install in some locales. localedef -i en_US -f UTF-8 en_US.UTF-8 export LC_ALL="en_US.UTF-8" export LANG="en_US.UTF-8" export LANGUAGE="en_US.UTF-8" # Check for a supported OS release. if [ -f /etc/os-release ]; then os_info="$(. /etc/os-release; printf '%s\n' "$ID" "$ID_LIKE" "$VERSION_ID" "$VERSION_CODENAME")" { read -r os_id; read -r os_id_like; read -r os_version_id; read -r os_version_codename || true; } <<< "$os_info" fi case "$os_id$os_version_id" in ubuntu16.04|ubuntu18.04|debian9|debian10|ubuntu20.04) ;; *) set +x cat <&2 echo "Insufficient RAM. Zulip requires at least 2GB of RAM." >&2 echo >&2 echo -e '\033[0m' >&2 exit 1 fi # Do package update, e.g. do `apt-get update` on Debian case " $os_id $os_id_like " in *' debian '*) # setup-apt-repo does an `apt-get update` "$ZULIP_PATH"/scripts/lib/setup-apt-repo ;; *' rhel '*) "$ZULIP_PATH"/scripts/lib/setup-yum-repo ;; esac # Check early for missing SSL certificates if [ "$PUPPET_CLASSES" = "zulip::voyager" ] && [ -z "$USE_CERTBOT""$SELF_SIGNED_CERT" ] && { ! [ -e "/etc/ssl/private/zulip.key" ] || ! [ -e "/etc/ssl/certs/zulip.combined-chain.crt" ]; }; then set +x cat <&2 echo "Installing packages failed; is network working and (on Ubuntu) the universe repository enabled?" >&2 echo >&2 echo -e '\033[0m' >&2 exit 1 fi ;; *' rhel '*) if ! yum install -y \ puppet git curl wget jq \ python python3 python-six python3-six crudini \ "${ADDITIONAL_PACKAGES[@]}"; then set +x echo -e '\033[0;31m' >&2 echo "Installing packages failed; is network working?" >&2 echo >&2 echo -e '\033[0m' >&2 exit 1 fi ;; esac if [ -n "$USE_CERTBOT" ]; then "$ZULIP_PATH"/scripts/setup/setup-certbot \ --no-zulip-conf --method=standalone \ "$EXTERNAL_HOST" --email "$ZULIP_ADMINISTRATOR" elif [ -n "$SELF_SIGNED_CERT" ]; then "$ZULIP_PATH"/scripts/setup/generate-self-signed-cert \ --exists-ok "${EXTERNAL_HOST:-$(hostname)}" fi # Create and activate a virtualenv if [ "$VIRTUALENV_NEEDED" = "yes" ]; then "$ZULIP_PATH"/scripts/lib/create-production-venv "$ZULIP_PATH" "$ZULIP_PATH"/scripts/lib/create-thumbor-venv "$ZULIP_PATH" fi "$ZULIP_PATH"/scripts/lib/install-node # Generate /etc/zulip/zulip.conf . mkdir -p /etc/zulip ( cat </dev/null # root@host# apt install rabbitmq-server # root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null # install ok installed # root@host# apt remove rabbitmq-server # root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null # deinstall ok config-files # root@host# apt purge rabbitmq-server # root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null # unknown ok not-installed # # (There are more possibilities in the case of dpkg errors.) Here # we are checking for either empty or not-installed. if ! dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null | grep -vq ' not-installed$'; then cat < /etc/zulip/zulip.conf case ",$PUPPET_CLASSES," in *,zulip::voyager,* | *,zulip::dockervoyager,* | *,zulip::app_frontend,*) if [ -z "$NO_OVERWRITE_SETTINGS" ] || ! [ -e "/etc/zulip/settings.py" ]; then cp -a "$ZULIP_PATH"/zproject/prod_settings_template.py /etc/zulip/settings.py if [ -n "$EXTERNAL_HOST" ]; then sed -i "s/^EXTERNAL_HOST =.*/EXTERNAL_HOST = '$EXTERNAL_HOST'/" /etc/zulip/settings.py fi if [ -n "$ZULIP_ADMINISTRATOR" ]; then sed -i "s/^ZULIP_ADMINISTRATOR =.*/ZULIP_ADMINISTRATOR = '$ZULIP_ADMINISTRATOR'/" /etc/zulip/settings.py fi fi ln -nsf /etc/zulip/settings.py "$ZULIP_PATH"/zproject/prod_settings.py "$ZULIP_PATH"/scripts/setup/generate_secrets.py --production ;; esac "$ZULIP_PATH"/scripts/zulip-puppet-apply -f case " $os_id $os_id_like " in *' debian '*) SUPERVISOR_CONF_DIR="/etc/supervisor/conf.d" ;; *' rhel '*) SUPERVISOR_CONF_DIR="/etc/supervisord.d/conf.d" ;; esac # Detect which features were selected for the below set +e [ -e "/etc/init.d/nginx" ]; has_nginx=$? [ -e "$SUPERVISOR_CONF_DIR/zulip.conf" ]; has_appserver=$? [ -e "/etc/cron.d/rabbitmq-numconsumers" ]; has_rabbit=$? [ -e "/etc/init.d/postgresql" ]; has_postgres=$? set -e # Docker service setup is done in the docker config, not here if [ "$DEPLOYMENT_TYPE" = "dockervoyager" ]; then has_nginx=1 has_appserver=0 has_rabbit=1 has_postgres=1 fi if [ -n "$POSTGRES_MISSING_DICTIONARIES" ]; then crudini --set /etc/zulip/zulip.conf postgresql missing_dictionaries true fi if [ -n "$REMOTE_POSTGRES" ]; then has_postgres=1 fi # These server restarting bits should be moveable into puppet-land, ideally case " $os_id $os_id_like " in *' debian '*) apt-get -y upgrade ;; *' rhel '*) # No action is required because `yum update` already does upgrade. ;; esac if [ "$has_nginx" = 0 ]; then # Check nginx was configured properly now that we've installed it. # Most common failure mode is certs not having been installed. nginx -t || ( set +x cat </dev/null; then set +x cat <