#!/bin/sh ## The contents of this file are subject to the Mozilla Public License ## Version 1.1 (the "License"); you may not use this file except in ## compliance with the License. You may obtain a copy of the License ## at http://www.mozilla.org/MPL/ ## ## Software distributed under the License is distributed on an "AS IS" ## basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See ## the License for the specific language governing rights and ## limitations under the License. ## ## The Original Code is RabbitMQ. ## ## The Initial Developer of the Original Code is GoPivotal, Inc. ## Copyright (c) 2007-2017 Pivotal Software, Inc. All rights reserved. ## set -e # Get default settings with user overrides for (RABBITMQ_) # Non-empty defaults should be set in rabbitmq-env . `dirname $0`/rabbitmq-env RABBITMQ_START_RABBIT= [ "x" = "x$RABBITMQ_ALLOW_INPUT" ] && RABBITMQ_START_RABBIT=" -noinput" [ "x" = "x$RABBITMQ_NODE_ONLY" ] && RABBITMQ_START_RABBIT="$RABBITMQ_START_RABBIT -s $RABBITMQ_BOOT_MODULE boot " case "$(uname -s)" in CYGWIN*) # we make no attempt to record the cygwin pid; rabbitmqctl wait # will not be able to make sense of it anyway ;; *) # When -detached is passed, we don't write the pid, since it'd be the # wrong one detached="" for opt in "$@"; do if [ "$opt" = "-detached" ]; then detached="true" fi done if [ $detached ]; then echo "Warning: PID file not written; -detached was passed." 1>&2 else RABBITMQ_PID_DIR="$(dirname ${RABBITMQ_PID_FILE})" EX_CANTCREAT=73 # Standard exit code from sysexits(2) if ! mkdir -p "$RABBITMQ_PID_DIR"; then # Better diagnostics - 'mkdir -p' reports only the first directory in chain that # it fails to create echo "Failed to create directory: $RABBITMQ_PID_DIR" exit $EX_CANTCREAT fi if ! echo $$ > ${RABBITMQ_PID_FILE}; then # Better diagnostics - otherwise the only report in logs is about failed 'echo' # command, but without any other details: neither what script has failed nor what # file output was redirected to. echo "Failed to write pid file: ${RABBITMQ_PID_FILE}" exit $EX_CANTCREAT fi fi esac RABBITMQ_EBIN_ROOT="${RABBITMQ_HOME}/ebin" [ "$NOTIFY_SOCKET" ] && RUNNING_UNDER_SYSTEMD=true set +e RABBITMQ_ADVANCED_CONFIG_FILE_NOEX="${RABBITMQ_ADVANCED_CONFIG_FILE%.*}" if [ "${RABBITMQ_ADVANCED_CONFIG_FILE_NOEX}.config" = "${RABBITMQ_ADVANCED_CONFIG_FILE}" ]; then RABBITMQ_ADVANCED_CONFIG_FILE="${RABBITMQ_ADVANCED_CONFIG_FILE_NOEX}" fi # `net_kernel:start/1` will fail in `longnames` mode when erlang is # unable to determine FQDN of a node (with a dot in it). But `erl` # itself has some magic that still allow it to start when you # explicitly specify host (a.la `erl -name test@localhost`). # # It's not possible to communicate with this node, unless it's a # connection initiator. But as prelaunch IS an initiator, it doesn't # matter what we actually put here. But `localhost` sounds good # enough. RABBITMQ_PRELAUNCH_NODENAME="rabbitmqprelaunch${$}@localhost" # NOTIFY_SOCKET is needed here to prevent epmd from impersonating the # success of our startup sequence to systemd. NOTIFY_SOCKET= \ RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \ ERL_CRASH_DUMP=$ERL_CRASH_DUMP \ RABBITMQ_DIST_PORT=$RABBITMQ_DIST_PORT \ ${ERL_DIR}erl -pa "$RABBITMQ_EBIN_ROOT" \ -boot "${CLEAN_BOOT_FILE}" \ -noinput \ -hidden \ -s rabbit_prelaunch \ ${RABBITMQ_NAME_TYPE} ${RABBITMQ_PRELAUNCH_NODENAME} \ -conf_advanced "${RABBITMQ_ADVANCED_CONFIG_FILE}" \ -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \ -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \ -extra "${RABBITMQ_NODENAME}" PRELAUNCH_RESULT=$? if [ ${PRELAUNCH_RESULT} = 2 ] ; then # dist port is mentioned in config, so do not set it true elif [ ${PRELAUNCH_RESULT} = 0 ] ; then # dist port is not mentioned in the config file, we can set it RABBITMQ_DIST_ARG="-kernel inet_dist_listen_min ${RABBITMQ_DIST_PORT} -kernel inet_dist_listen_max ${RABBITMQ_DIST_PORT}" else exit ${PRELAUNCH_RESULT} fi if [ ! -d ${RABBITMQ_SCHEMA_DIR} ]; then mkdir -p "${RABBITMQ_SCHEMA_DIR}" fi if [ ! -d ${RABBITMQ_GENERATED_CONFIG_DIR} ]; then mkdir -p "${RABBITMQ_GENERATED_CONFIG_DIR}" fi if [ ! -f "${RABBITMQ_SCHEMA_DIR}/rabbit.schema" ]; then cp "${RABBITMQ_HOME}/priv/schema/rabbit.schema" "${RABBITMQ_SCHEMA_DIR}" fi # The default allocation strategy RabbitMQ is using was introduced # in Erlang/OTP 20.2.3. Earlier Erlang versions fail to start with # this configuration. We therefore need to ensure that erl accepts # these values before we can use them. # # The defaults are meant to reduce RabbitMQ's memory usage and help # it reclaim memory at the cost of a slight decrease in performance # (due to an increase in memory operations). These defaults can be # overriden using the RABBITMQ_SERVER_ERL_ARGS variable. RABBITMQ_DEFAULT_ALLOC_ARGS="+MBas ageffcbf +MHas ageffcbf +MBlmbcs 512 +MHlmbcs 512 +MMmcs 30" ${ERL_DIR}erl ${RABBITMQ_DEFAULT_ALLOC_ARGS} \ -boot "${CLEAN_BOOT_FILE}" \ -noinput -eval 'halt(0)' 2>/dev/null if [ $? != 0 ] ; then RABBITMQ_DEFAULT_ALLOC_ARGS= fi set -e RABBITMQ_CONFIG_FILE_NOEX="${RABBITMQ_CONFIG_FILE%.*}" if [ "${RABBITMQ_CONFIG_FILE_NOEX}.config" = "${RABBITMQ_CONFIG_FILE}" ]; then if [ -f "${RABBITMQ_CONFIG_FILE}" ]; then RABBITMQ_CONFIG_ARG="-config ${RABBITMQ_CONFIG_FILE_NOEX}" fi elif [ "${RABBITMQ_CONFIG_FILE_NOEX}.conf" = "${RABBITMQ_CONFIG_FILE}" ]; then RABBITMQ_CONFIG_ARG="-conf ${RABBITMQ_CONFIG_FILE_NOEX} \ -conf_dir ${RABBITMQ_GENERATED_CONFIG_DIR} \ -conf_script_dir `dirname $0` \ -conf_schema_dir ${RABBITMQ_SCHEMA_DIR}" if [ -f "${RABBITMQ_ADVANCED_CONFIG_FILE}.config" ]; then RABBITMQ_CONFIG_ARG="${RABBITMQ_CONFIG_ARG} \ -conf_advanced ${RABBITMQ_ADVANCED_CONFIG_FILE} \ -config ${RABBITMQ_ADVANCED_CONFIG_FILE}" fi else if [ -f "${RABBITMQ_CONFIG_FILE}.config" ]; then RABBITMQ_CONFIG_ARG="-config ${RABBITMQ_CONFIG_FILE}" elif [ -f "${RABBITMQ_CONFIG_FILE}.conf" ]; then RABBITMQ_CONFIG_ARG="-conf ${RABBITMQ_CONFIG_FILE} \ -conf_dir ${RABBITMQ_GENERATED_CONFIG_DIR} \ -conf_script_dir `dirname $0` \ -conf_schema_dir ${RABBITMQ_SCHEMA_DIR}" if [ -f "${RABBITMQ_ADVANCED_CONFIG_FILE}.config" ]; then RABBITMQ_CONFIG_ARG="${RABBITMQ_CONFIG_ARG} \ -conf_advanced ${RABBITMQ_ADVANCED_CONFIG_FILE} \ -config ${RABBITMQ_ADVANCED_CONFIG_FILE}" fi fi fi RABBITMQ_LISTEN_ARG= [ "x" != "x$RABBITMQ_NODE_PORT" ] && [ "x" != "x$RABBITMQ_NODE_IP_ADDRESS" ] && RABBITMQ_LISTEN_ARG="-rabbit tcp_listeners [{\""${RABBITMQ_NODE_IP_ADDRESS}"\","${RABBITMQ_NODE_PORT}"}]" # If $RABBITMQ_LOGS is '-', send all log messages to stdout. This is # particularly useful for Docker images. if [ "$RABBITMQ_LOGS" = '-' ]; then SASL_ERROR_LOGGER=tty RABBIT_LAGER_HANDLER=tty RABBITMQ_LAGER_HANDLER_UPGRADE=tty else SASL_ERROR_LOGGER=false RABBIT_LAGER_HANDLER='"'${RABBITMQ_LOGS}'"' RABBITMQ_LAGER_HANDLER_UPGRADE='"'${RABBITMQ_UPGRADE_LOG}'"' fi # Bump ETS table limit to 50000 if [ "x" = "x$ERL_MAX_ETS_TABLES" ]; then ERL_MAX_ETS_TABLES=50000 fi # we need to turn off path expansion because some of the vars, notably # RABBITMQ_SERVER_ERL_ARGS, contain terms that look like globs and # there is no other way of preventing their expansion. set -f # Lazy initialization of threed pool size - if it wasn't set # explicitly. This parameter is only needed when server is starting, # so it makes no sense to do this calculations in rabbitmq-env or # rabbitmq-defaults scripts. ensure_thread_pool_size() { if [ -z "${RABBITMQ_IO_THREAD_POOL_SIZE}" ]; then RABBITMQ_IO_THREAD_POOL_SIZE=$( ${ERL_DIR}erl -pa "$RABBITMQ_EBIN_ROOT" \ -boot "${CLEAN_BOOT_FILE}" \ -noinput \ -s rabbit_misc report_default_thread_pool_size ) fi } start_rabbitmq_server() { # "-pa ${RABBITMQ_SERVER_CODE_PATH}" should be the very first # command-line argument. In case of using cached HiPE-compilation, # this will allow for compiled versions of erlang built-in modules # (e.g. lists) to be loaded. ensure_thread_pool_size check_start_params && RABBITMQ_CONFIG_FILE=$RABBITMQ_CONFIG_FILE \ ERL_MAX_ETS_TABLES=$ERL_MAX_ETS_TABLES \ ERL_CRASH_DUMP=$ERL_CRASH_DUMP \ exec ${ERL_DIR}erl \ -pa ${RABBITMQ_SERVER_CODE_PATH} ${RABBITMQ_EBIN_ROOT} \ ${RABBITMQ_START_RABBIT} \ ${RABBITMQ_NAME_TYPE} ${RABBITMQ_NODENAME} \ -boot "${SASL_BOOT_FILE}" \ ${RABBITMQ_CONFIG_ARG} \ +W w \ +A ${RABBITMQ_IO_THREAD_POOL_SIZE} \ ${RABBITMQ_DEFAULT_ALLOC_ARGS} \ ${RABBITMQ_SERVER_ERL_ARGS} \ +K true \ -kernel inet_default_connect_options "[{nodelay,true}]" \ ${RABBITMQ_SERVER_ADDITIONAL_ERL_ARGS} \ ${RABBITMQ_LISTEN_ARG} \ -sasl errlog_type error \ -sasl sasl_error_logger "$SASL_ERROR_LOGGER" \ -rabbit lager_log_root "\"$RABBITMQ_LOG_BASE\"" \ -rabbit lager_default_file "$RABBIT_LAGER_HANDLER" \ -rabbit lager_upgrade_file "$RABBITMQ_LAGER_HANDLER_UPGRADE" \ -rabbit enabled_plugins_file "\"$RABBITMQ_ENABLED_PLUGINS_FILE\"" \ -rabbit plugins_dir "\"$RABBITMQ_PLUGINS_DIR\"" \ -rabbit plugins_expand_dir "\"$RABBITMQ_PLUGINS_EXPAND_DIR\"" \ -os_mon start_cpu_sup false \ -os_mon start_disksup false \ -os_mon start_memsup false \ -mnesia dir "\"${RABBITMQ_MNESIA_DIR}\"" \ ${RABBITMQ_SERVER_START_ARGS} \ ${RABBITMQ_DIST_ARG} \ "$@" } stop_rabbitmq_server() { RABBITMQCTL="$(dirname "$0")/rabbitmqctl" if ${RABBITMQCTL} -n ${RABBITMQ_NODENAME} status >/dev/null 2>&1; then ${RABBITMQCTL} -n ${RABBITMQ_NODENAME} stop fi } check_start_params() { check_not_empty RABBITMQ_BOOT_MODULE check_not_empty RABBITMQ_NAME_TYPE check_not_empty RABBITMQ_NODENAME check_not_empty SASL_BOOT_FILE check_not_empty RABBITMQ_IO_THREAD_POOL_SIZE } check_not_empty() { local name="${1:?}" local value eval value=\$$name if [ -z "$value" ]; then echo "Error: ENV variable should be defined: $1. Please check rabbitmq-env, rabbitmq-defaults, and ${RABBITMQ_CONF_ENV_FILE} script files" exit 78 fi } if [ "$RABBITMQ_ALLOW_INPUT" -o "$RUNNING_UNDER_SYSTEMD" -o "$detached" ]; then # Run erlang VM directly, completely replacing current shell # process - so the pid file written in the code above will be # valid (unless detached, which is also handled in the code # above). # # And also this is the correct mode to run the broker under # systemd - there is no need in a proxy process that converts # signals to graceful shutdown command, the unit file should already # contain instructions for graceful shutdown. Also by removing # this additional process we could simply use value returned by # `os:getpid/0` for a systemd ready notification. start_rabbitmq_server "$@" else # When RabbitMQ runs in the foreground but the Erlang shell is # disabled, we setup signal handlers to stop RabbitMQ properly. This # is at least useful in the case of Docker. # The Erlang VM should ignore SIGINT. RABBITMQ_SERVER_START_ARGS="${RABBITMQ_SERVER_START_ARGS} ${RABBITMQ_IGNORE_SIGINT_FLAG}" # Signal handlers. They all stop RabbitMQ properly, using # rabbitmqctl stop. This script will exit with different exit codes: # SIGHUP SIGTERM SIGTSTP # Exits 0 since this is considered a normal process termination. # SIGINT # Exits 128 + $signal_number where $signal_number is 2 for SIGINT (see # http://pubs.opengroup.org/onlinepubs/009695399/utilities/kill.html). # This is considered an abnormal process termination. Normally, we # don't need to specify this exit code because the shell propagates it. # Unfortunately, the signal handler doesn't work as expected in Dash, # thus we need to explicitely restate the exit code. trap "stop_rabbitmq_server; exit 0" HUP TERM TSTP trap "stop_rabbitmq_server; exit 130" INT start_rabbitmq_server "$@" & rabbitmq_server_pid=$! # Block until RabbitMQ exits or a signal is caught. # Waits for last command (which is start_rabbitmq_server) # # The "|| true" is here to work around an issue with Dash. Normally # in a Bourne shell, if `wait` is interrupted by a signal, the # signal handlers defined above are executed and the script # terminates with the exit code of `wait` (unless the signal handler # overrides that). # In the case of Dash, it looks like `set -e` (set at the beginning # of this script) gets precedence over signal handling. Therefore, # when `wait` is interrupted, its exit code is non-zero and because # of `set -e`, the script terminates immediately without running the # signal handler. To work around this issue, we use "|| true" to # force that statement to succeed and the signal handler to properly # execute. Because the statement below has an exit code of 0, the # signal handler has to restate the expected exit code. wait $rabbitmq_server_pid || true fi