mirror of
https://github.com/zulip/zulip.git
synced 2026-06-24 21:08:25 +08:00
This commits adds the necessary puppet configuration and installer/upgrade code for installing and managing the thumbor service in production. This configuration is gated by the 'thumbor.pp' manifest being enabled (which is not yet the default), and so this commit should have no effect in a default Zulip production environment (or in the long term, in any Zulip production server that isn't using thumbor). Credit for this effort is shared by @TigorC (who initiated the work on this project), @joshland (who did a great deal of work on this and got it working during PyCon 2017) and @adnrs96, who completed the work.
325 lines
9.8 KiB
Bash
Executable File
325 lines
9.8 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -e
|
|
|
|
usage() {
|
|
cat <<EOF
|
|
Usage:
|
|
install --hostname=zulip.example.com --email=admin@example.com [options...]
|
|
install --help
|
|
|
|
Other options:
|
|
--certbot
|
|
--self-signed-cert
|
|
--no-init-db
|
|
|
|
The --hostname and --email options are required,
|
|
unless --no-init-db is set and --certbot is not.
|
|
|
|
EOF
|
|
exit 0
|
|
};
|
|
|
|
# Shell option parsing. Over time, we'll want to move some of the
|
|
# environment variables below into this self-documenting system.
|
|
args="$(getopt -o '' --long help,no-init-db,self-signed-cert,certbot,hostname:,email: -n "$0" -- "$@")"
|
|
eval "set -- $args"
|
|
while true; do
|
|
case "$1" in
|
|
--help) usage;;
|
|
--self-signed-cert) SELF_SIGNED_CERT=1; shift;;
|
|
--certbot) USE_CERTBOT=1; shift;;
|
|
--hostname) EXTERNAL_HOST="$2"; shift; shift;;
|
|
--email) ZULIP_ADMINISTRATOR="$2"; shift; shift;;
|
|
--no-init-db) NO_INIT_DB=1; shift;;
|
|
--) shift; break;;
|
|
esac
|
|
done
|
|
|
|
if [ "$#" -gt 0 ]; then
|
|
usage
|
|
fi
|
|
|
|
## Options from environment variables.
|
|
#
|
|
# Specify options for apt.
|
|
APT_OPTIONS="${APT_OPTIONS:-}"
|
|
# Install additional packages using apt.
|
|
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
|
|
echo "error: --self-signed-cert and --certbot are incompatible" >&2
|
|
echo >&2
|
|
usage
|
|
fi
|
|
|
|
if [ -z "$EXTERNAL_HOST" ] || [ -z "$ZULIP_ADMINISTRATOR" ]; then
|
|
if [ -n "$USE_CERTBOT" ] || [ -z "$NO_INIT_DB" ]; then
|
|
usage
|
|
fi
|
|
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.
|
|
export LC_ALL="en_US.UTF-8"
|
|
|
|
# Check for a supported OS release.
|
|
apt-get install -y lsb-release
|
|
os_release="$(lsb_release -sc)"
|
|
case "$os_release" in
|
|
trusty|xenial|stretch|bionic) ;;
|
|
*)
|
|
set +x
|
|
cat <<EOF
|
|
|
|
Unsupported OS release: $os_release
|
|
|
|
Zulip in production is supported only on:
|
|
- Debian 9 "stretch"
|
|
- Ubuntu 14.04 LTS "trusty" (deprecated)
|
|
- Ubuntu 16.04 LTS "xenial"
|
|
- Ubuntu 18.04 LTS "bionic"
|
|
|
|
For more information, see:
|
|
https://zulip.readthedocs.io/en/latest/production/requirements.html
|
|
EOF
|
|
exit 1
|
|
esac
|
|
|
|
# Check for at least ~1.9GB of RAM before starting installation;
|
|
# otherwise users will find out about insufficient RAM via weird
|
|
# errors like a segfault running `pip install`.
|
|
mem_kb=$(cat /proc/meminfo | head -n1 | awk '{print $2}')
|
|
if [ "$mem_kb" -lt 1900000 ]; then
|
|
echo "Insufficient RAM. Zulip requires at least 2GB of RAM."
|
|
exit 1
|
|
fi
|
|
|
|
# setup-apt-repo does an `apt-get update`
|
|
"$ZULIP_PATH"/scripts/lib/setup-apt-repo
|
|
|
|
# Handle issues around upstart on Ubuntu Xenial
|
|
"$ZULIP_PATH"/scripts/lib/check-upstart
|
|
|
|
# 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 <<EOF
|
|
|
|
No SSL certificate found. One or both required files is missing:
|
|
/etc/ssl/private/zulip.key
|
|
/etc/ssl/certs/zulip.combined-chain.crt
|
|
|
|
Suggested solutions:
|
|
* For most sites, the --certbot option is recommended.
|
|
* If you have your own key and cert, see docs linked below
|
|
for how to install them.
|
|
* For non-production testing, try the --self-signed-cert option.
|
|
|
|
For help and more details, see our SSL documentation:
|
|
https://zulip.readthedocs.io/en/latest/production/ssl-certificates.html
|
|
|
|
Once fixed, just rerun scripts/setup/install; it'll pick up from here!
|
|
|
|
EOF
|
|
exit 1
|
|
fi
|
|
|
|
apt-get -y dist-upgrade $APT_OPTIONS
|
|
apt-get install -y \
|
|
puppet git curl wget \
|
|
python python3 python-six python3-six crudini \
|
|
$ADDITIONAL_PACKAGES
|
|
|
|
if [ -n "$USE_CERTBOT" ]; then
|
|
"$ZULIP_PATH"/scripts/setup/setup-certbot \
|
|
--no-zulip-conf --method=standalone \
|
|
--hostname "$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 <<EOF
|
|
[machine]
|
|
puppet_classes = $PUPPET_CLASSES
|
|
deploy_type = $DEPLOYMENT_TYPE
|
|
EOF
|
|
|
|
# Note: there are four dpkg-query outputs to consider:
|
|
#
|
|
# root@host# dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/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 [ -n "$TRAVIS" ] || ! dpkg-query --showformat '${Status}\n' -W rabbitmq-server 2>/dev/null | grep -vq ' not-installed$'; then
|
|
cat <<EOF
|
|
|
|
[rabbitmq]
|
|
nodename = zulip@localhost
|
|
EOF
|
|
fi
|
|
|
|
if [ -n "$USE_CERTBOT" ]; then
|
|
cat <<EOF
|
|
|
|
[certbot]
|
|
auto_renew = yes
|
|
EOF
|
|
fi
|
|
) > /etc/zulip/zulip.conf
|
|
|
|
"$ZULIP_PATH"/scripts/zulip-puppet-apply -f
|
|
|
|
# Detect which features were selected for the below
|
|
set +e
|
|
[ -e "/etc/init.d/camo" ]; has_camo=$?
|
|
[ -e "/etc/init.d/nginx" ]; has_nginx=$?
|
|
[ -e "/etc/supervisor/conf.d/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_camo=1
|
|
has_nginx=1
|
|
has_appserver=0
|
|
has_rabbit=1
|
|
has_postgres=1
|
|
fi
|
|
|
|
# These server restarting bits should be moveable into puppet-land, ideally
|
|
apt-get -y upgrade
|
|
|
|
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 <<EOF
|
|
|
|
Verifying the Zulip nginx configuration failed!
|
|
|
|
This is almost always a problem with your SSL certificates. See:
|
|
https://zulip.readthedocs.io/en/latest/production/ssl-certificates.html
|
|
|
|
Once fixed, just rerun scripts/setup/install; it'll pick up from here!
|
|
|
|
EOF
|
|
exit 1
|
|
)
|
|
service nginx restart
|
|
fi
|
|
|
|
if [ "$has_appserver" = 0 ]; then
|
|
"$ZULIP_PATH"/scripts/setup/generate_secrets.py --production
|
|
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
|
|
ln -nsf /etc/zulip/settings.py "$ZULIP_PATH"/zproject/prod_settings.py
|
|
fi
|
|
|
|
# Restart camo since generate_secrets.py likely replaced its secret key
|
|
if [ "$has_camo" = 0 ]; then
|
|
# Cut off stdin because a bug in the Debian packaging for camo
|
|
# causes our stdin to leak to the daemon, which can cause tools
|
|
# invoking the installer to hang.
|
|
# TODO: fix in Debian too.
|
|
service camo restart </dev/null
|
|
fi
|
|
|
|
if [ "$has_rabbit" = 0 ]; then
|
|
if ! rabbitmqctl status >/dev/null; then
|
|
set +x
|
|
cat <<EOF
|
|
|
|
RabbitMQ seems to not have started properly after the installation process.
|
|
Often this is caused by misconfigured /etc/hosts in virtualized environments.
|
|
For more information, see:
|
|
https://github.com/zulip/zulip/issues/53#issuecomment-143805121
|
|
|
|
EOF
|
|
exit 1
|
|
fi
|
|
"$ZULIP_PATH"/scripts/setup/configure-rabbitmq
|
|
fi
|
|
|
|
if [ "$has_postgres" = 0 ]; then
|
|
"$ZULIP_PATH"/scripts/setup/postgres-init-db
|
|
fi
|
|
|
|
if [ "$has_appserver" = 0 ]; then
|
|
deploy_path=$("$ZULIP_PATH"/scripts/lib/zulip_tools.py make_deploy_path)
|
|
mv "$ZULIP_PATH" "$deploy_path"
|
|
ln -nsf /home/zulip/deployments/next "$ZULIP_PATH"
|
|
ln -nsf "$deploy_path" /home/zulip/deployments/next
|
|
ln -nsf "$deploy_path" /home/zulip/deployments/current
|
|
ln -nsf /etc/zulip/settings.py "$deploy_path"/zproject/prod_settings.py
|
|
mkdir -p "$deploy_path"/prod-static/serve
|
|
cp -rT "$deploy_path"/prod-static/serve /home/zulip/prod-static
|
|
chown -R zulip:zulip /home/zulip /var/log/zulip /etc/zulip/settings.py
|
|
|
|
if ! [ -e "/home/zulip/prod-static/generated" ]; then
|
|
# If we're installing from a git checkout, we need to run
|
|
# `tools/update-prod-static` in order to build the static
|
|
# assets.
|
|
su zulip -c "/home/zulip/deployments/current/tools/update-prod-static --authors-not-required"
|
|
fi
|
|
fi
|
|
|
|
if [ -e "/var/run/supervisor.sock" ]; then
|
|
chown zulip:zulip /var/run/supervisor.sock
|
|
fi
|
|
|
|
if [ -n "$NO_INIT_DB" ]; then
|
|
set +x
|
|
cat <<EOF
|
|
|
|
Success!
|
|
|
|
Stopping because --no-init-db was passed. To complete the installation, run:
|
|
|
|
su zulip -c /home/zulip/deployments/current/scripts/setup/initialize-database
|
|
EOF
|
|
exit 0
|
|
fi
|
|
|
|
su zulip -c '/home/zulip/deployments/current/scripts/setup/initialize-database --quiet'
|
|
|
|
su zulip -c '/home/zulip/deployments/current/manage.py generate_realm_creation_link'
|