emqx/bin/emqx
2021-12-22 15:43:43 -03:00

465 lines
14 KiB
Bash
Executable File

#!/bin/bash
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
set -euo pipefail
BASE="$(cd "$(dirname "$(readlink "$0" || echo "$0")")"/..; pwd -P)"
# shellcheck disable=SC1090,SC1091
source "$BASE/bin/common_defs.sh"
# shellcheck disable=SC1090,SC1091
source "$BASE/bin/common_functions.sh"
# Make sure log directory exists
mkdir -p "$RUNNER_LOG_DIR"
# Make sure data directory exists
mkdir -p "$RUNNER_DATA_DIR"
# Make sure data/configs exists
mkdir -p "$CONFIGS_DIR"
usage() {
local command="$1"
case "$command" in
start)
echo "Start EMQ X service in daemon mode"
;;
stop)
echo "Stop the running EMQ X program"
;;
restart|reboot)
echo "Restart $EMQX_DESCRIPTION"
;;
pid)
echo "Print out $EMQX_DESCRIPTION process identifier"
;;
ping)
echo "Check if the $EMQX_DESCRIPTION node is up and running"
echo "This command exit with 0 silently if node is running"
;;
escript)
echo "Execute a escript using the Erlang runtime from EMQ X package installation"
echo "For example $REL_NAME escript /path/to/my/escript my_arg1 my_arg2"
;;
attach)
echo "This command is applicable when $EMQX_DESCRIPTION is started in daemon"
echo "mode. it attaches the current shell to EMQ X's control console"
echo "through a named pipe"
echo "WARNING: try to use the safer alternative, remote_console command."
;;
remote_console)
echo "Start a dummy Erlang node and hidden-connect $EMQX_DESCRIPTION to"
echo "with an interactive Erlang shell"
;;
console)
echo "Boot up $EMQX_DESCRIPTION service in an interactive Erlang shell"
echo "This command is useful for troubleshooting"
;;
console_clean)
echo "This command does NOT boot up the $EMQX_DESCRIPTION service"
echo "It only starts an interactive Erlang console with all the"
echo "EMQ X code available"
;;
foreground)
echo "Start $EMQX_DESCRIPTION in foreground mode"
;;
ertspath)
echo "Print path to Erlang runtime dir"
;;
rpc)
echo "Usge $REL_NAME rpc MODULE FUNCTION [ARGS, ...]"
echo "Connect to the $EMQX_DESCRIPTION node and make an Erlang RPC"
echo "The result of the RPC call must be 'ok'"
echo "This command blocks for at most 60 seconds in case the node"
echo "does not reply the call in time"
;;
rpcterms)
echo "Usge $REL_NAME rpcterms MODULE FUNCTION [ARGS, ...]"
echo "Connect to the $EMQX_DESCRIPTION node and make an Erlang RPC"
echo "The result of the RPC call is pretty-printed as an Erlang term"
;;
root_dir)
echo "Print EMQ X installation root dir"
;;
eval)
echo "Evaluate an Erlang expression in the EMQ X node"
;;
versions)
echo "List installed EMQ X versions and their status"
;;
unpack)
echo "Usage: $REL_NAME unpack [VERSION]"
echo "Unpacks a release package VERSION, it assumes that this"
echo "release package tarball has already been deployed at one"
echo "of the following locations:"
echo " releases/<relname>-<version>.tar.gz"
echo " releases/<relname>-<version>.zip"
;;
install)
echo "Usage: $REL_NAME install [VERSION]"
echo "Installs a release package VERSION, it assumes that this"
echo "release package tarball has already been deployed at one"
echo "of the following locations:"
echo " releases/<relname>-<version>.tar.gz"
echo " releases/<relname>-<version>.zip"
echo ""
echo " --no-permanent Install release package VERSION but"
echo " don't make it permanent"
;;
uninstall)
echo "Usage: $REL_NAME uninstall [VERSION]"
echo "Uninstalls a release VERSION, it will only accept"
echo "versions that are not currently in use"
;;
upgrade)
echo "Usage: $REL_NAME upgrade [VERSION]"
echo "Upgrades the currently running release to VERSION, it assumes"
echo "that a release package tarball has already been deployed at one"
echo "of the following locations:"
echo " releases/<relname>-<version>.tar.gz"
echo " releases/<relname>-<version>.zip"
echo ""
echo " --no-permanent Install release package VERSION but"
echo " don't make it permanent"
;;
downgrade)
echo "Usage: $REL_NAME downgrade [VERSION]"
echo "Downgrades the currently running release to VERSION, it assumes"
echo "that a release package tarball has already been deployed at one"
echo "of the following locations:"
echo " releases/<relname>-<version>.tar.gz"
echo " releases/<relname>-<version>.zip"
echo ""
echo " --no-permanent Install release package VERSION but"
echo " don't make it permanent"
;;
*)
echo "Usage: $REL_NAME {start|ertspath|foreground|stop|pid|ping|console|console_clean|attach|remote_console|upgrade|downgrade|install|uninstall|versions|escript|ctl|rpc|rpcterms|eval|root_dir} <help>"
;;
esac
}
COMMAND="${1:-}"
if [ "${2:-}" = 'help' ]; then
## 'ctl' command has its own usage info
if [ "$COMMAND" != 'ctl' ]; then
usage "$COMMAND"
exit 0
fi
fi
if ! check_erlang_start >/dev/null 2>&1; then
BUILT_ON="$(head -1 "${REL_DIR}/BUILT_ON")"
## failed to start, might be due to missing libs, try to be portable
export LD_LIBRARY_PATH="$DYNLIBS_DIR:$LD_LIBRARY_PATH"
if ! check_erlang_start; then
## it's hopeless
echoerr "FATAL: Unable to start Erlang."
echoerr "Please make sure openssl-1.1.1 (libcrypto) and libncurses are installed."
echoerr "Also ensure it's running on the correct platform,"
echoerr "this EMQ X release is built for $BUILT_ON"
exit 1
fi
echoerr "WARNING: There seem to be missing dynamic libs from the OS. Using libs from ${DYNLIBS_DIR}"
fi
# Make sure the user running this script is the owner and/or su to that user
check_user "$@"
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
fi
## IS_BOOT_COMMAND is set for later to inspect node name and cookie
## from hocon config (or env variable), which resides in
## `common_defs2.sh`.
case "${COMMAND}" in
start|console|console_clean|foreground)
IS_BOOT_COMMAND='yes'
;;
*)
IS_BOOT_COMMAND='no'
;;
esac
export IS_BOOT_COMMAND
# shellcheck disable=SC1090,SC1091
source "$BASE/bin/common_defs2.sh"
cd "$ROOTDIR"
case "${COMMAND}" in
start)
# Make sure a node IS not running
if relx_nodetool "ping" >/dev/null 2>&1; then
die "node_is_already_running!"
fi
# this flag passes down to console mode
# so we know it's intended to be run in daemon mode
export _EMQX_START_MODE="$COMMAND"
case "$COMMAND" in
start)
shift
START_OPTION="console"
HEART_OPTION="start"
;;
esac
export START_OPTION
RUN_PARAM="$*"
# Set arguments for the heart command
set -- "$RUNNER_SCRIPT" "$HEART_OPTION"
[ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM"
# Export the HEART_COMMAND
HEART_COMMAND="$RUNNER_SCRIPT $COMMAND"
export HEART_COMMAND
## See: http://erlang.org/doc/man/run_erl.html
# Export the RUN_ERL_LOG_GENERATIONS
export RUN_ERL_LOG_GENERATIONS=${RUN_ERL_LOG_GENERATIONS:-"5"}
# Export the RUN_ERL_LOG_MAXSIZE
export RUN_ERL_LOG_MAXSIZE=${RUN_ERL_LOG_MAXSIZE:-"10485760"}
mkdir -p "$PIPE_DIR"
"$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \
"$(relx_start_command)"
WAIT_TIME=${WAIT_FOR_ERLANG:-15}
if wait_for "$WAIT_TIME" 'relx_nodetool' 'ping'; then
echo "$EMQX_DESCRIPTION $REL_VSN is started successfully!"
exit 0
else
echo "$EMQX_DESCRIPTION $REL_VSN failed to start within ${WAIT_TIME} seconds,"
echo "see the output of '$0 console' for more information."
echo "If you want to wait longer, set the environment variable"
echo "WAIT_FOR_ERLANG to the number of seconds to wait."
exit 1
fi
;;
stop)
# Wait for the node to completely stop...
PID="$(relx_get_pid)"
if ! relx_nodetool "stop"; then
echoerr "Graceful shutdown failed PID=[$PID]"
exit 1
fi
WAIT_TIME="${WAIT_FOR_ERLANG_STOP:-60}"
if ! wait_for "$WAIT_TIME" 'is_down' "$PID"; then
msg="dangling after ${WAIT_TIME} seconds"
# also log to syslog
logger -t "${REL_NAME}[${PID}]" "STOP: $msg"
# log to user console
echoerr "stop failed, $msg"
echo "ERROR: $PID is still around"
ps -p "$PID"
exit 1
fi
logger -t "${REL_NAME}[${PID}]" "STOP: OK"
;;
restart|reboot)
echo "$EMQX_DESCRIPTION $REL_VSN is stopped: $("$RUNNER_BIN_DIR/$REL_NAME" stop)"
"$RUNNER_BIN_DIR/$REL_NAME" start
;;
pid)
## Get the VM's pid
if ! relx_get_pid; then
exit 1
fi
;;
ping)
assert_node_alive
echo pong
;;
escript)
## Run an escript under the node's environment
if ! relx_escript "$@"; then
exit 1
fi
;;
attach)
assert_node_alive
shift
exec "$BINDIR/to_erl" "$PIPE_DIR"
;;
remote_console)
assert_node_alive
shift
relx_rem_sh
;;
upgrade|downgrade|install|unpack|uninstall)
if [ -z "${2:-}" ]; then
echo "Missing version argument"
echo "Usage: $REL_NAME $COMMAND {version}"
exit 1
fi
shift
assert_node_alive
ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
"$COMMAND" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@"
;;
versions)
assert_node_alive
shift
ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
"versions" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@"
;;
console|console_clean)
# .boot file typically just $REL_NAME (ie, the app name)
# however, for debugging, sometimes start_clean.boot is useful.
# For e.g. 'setup', one may even want to name another boot script.
case "$COMMAND" in
console)
if [ -f "$REL_DIR/$REL_NAME.boot" ]; then
BOOTFILE="$REL_DIR/$REL_NAME"
else
BOOTFILE="$REL_DIR/start"
fi
;;
console_clean)
BOOTFILE="$REL_DIR/start_clean"
;;
esac
# set before generate_config
if [ "${_EMQX_START_MODE:-}" = '' ]; then
export EMQX_LOG__CONSOLE_HANDLER__ENABLE="${EMQX_LOG__CONSOLE_HANDLER__ENABLE:-true}"
fi
#generate app.config and vm.args
generate_config "$NAME_TYPE" "$NAME"
# Setup beam-required vars
EMU="beam"
PROGNAME="${0#*/}"
export EMU
export PROGNAME
# Store passed arguments since they will be erased by `set`
ARGS="$*"
# shellcheck disable=SC2086 # $CONFIG_ARGS $EPMD_ARG are supposed to be split by whitespace
# Build an array of arguments to pass to exec later on
# Build it here because this command will be used for logging.
set -- "$BINDIR/erlexec" \
-boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-mnesia dir "\"${MNESIA_DATA_DIR}\"" \
$CONFIG_ARGS $EPMD_ARG
# Log the startup
logger -t "${REL_NAME}[$$]" "EXEC: $* -- ${1+$ARGS}"
# Start the VM
exec "$@" -- ${1+$ARGS}
;;
foreground)
# start up the release in the foreground for use by runit
# or other supervision services
# set before generate_config
export EMQX_LOG__CONSOLE_HANDLER__ENABLE="${EMQX_LOG__CONSOLE_HANDLER__ENABLE:-true}"
#generate app.config and vm.args
generate_config "$NAME_TYPE" "$NAME"
[ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
FOREGROUNDOPTIONS="-noshell -noinput +Bd"
# Setup beam-required vars
EMU=beam
PROGNAME="${0#*/}"
export EMU
export PROGNAME
# Store passed arguments since they will be erased by `set`
ARGS="$*"
# shellcheck disable=SC2086 # $CONFIG_ARGS $EPMD_ARG are supposed to be split by whitespace
# Build an array of arguments to pass to exec later on
# Build it here because this command will be used for logging.
set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \
-boot "$REL_DIR/$BOOTFILE" -mode "$CODE_LOADING_MODE" \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-mnesia dir "\"${MNESIA_DATA_DIR}\"" \
$CONFIG_ARGS $EPMD_ARG
# Log the startup
logger -t "${REL_NAME}[$$]" "EXEC: $* -- ${1+$ARGS}"
# Start the VM
exec "$@" -- ${1+$ARGS}
;;
ertspath)
echo "$ERTS_PATH"
;;
ctl)
assert_node_alive
shift
relx_nodetool rpc_infinity emqx_ctl run_command "$@"
;;
rpc)
assert_node_alive
shift
relx_nodetool rpc "$@"
;;
rpcterms)
assert_node_alive
shift
relx_nodetool rpcterms "$@"
;;
root_dir)
assert_node_alive
shift
relx_nodetool "eval" 'code:root_dir()'
;;
eval)
assert_node_alive
shift
relx_nodetool "eval" "$@"
;;
*)
usage "$COMMAND"
exit 1
;;
esac
exit 0