emqx 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769
  1. #!/bin/bash
  2. # -*- tab-width:4;indent-tabs-mode:nil -*-
  3. # ex: ts=4 sw=4 et
  4. set -euo pipefail
  5. DEBUG="${DEBUG:-0}"
  6. if [ "$DEBUG" -eq 1 ]; then
  7. set -x
  8. fi
  9. ROOT_DIR="$(cd "$(dirname "$(readlink "$0" || echo "$0")")"/..; pwd -P)"
  10. # shellcheck disable=SC1090
  11. . "$ROOT_DIR"/releases/emqx_vars
  12. # defined in emqx_vars
  13. export RUNNER_ROOT_DIR
  14. export RUNNER_ETC_DIR
  15. export REL_VSN
  16. RUNNER_SCRIPT="$RUNNER_BIN_DIR/$REL_NAME"
  17. CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
  18. REL_DIR="$RUNNER_ROOT_DIR/releases/$REL_VSN"
  19. SCHEMA_MOD=emqx_conf_schema
  20. WHOAMI=$(whoami)
  21. # Make sure log directory exists
  22. mkdir -p "$RUNNER_LOG_DIR"
  23. # Make sure data directory exists
  24. mkdir -p "$RUNNER_DATA_DIR"
  25. # Make sure data/configs exists
  26. CONFIGS_DIR="$RUNNER_DATA_DIR/configs"
  27. mkdir -p "$CONFIGS_DIR"
  28. # hocon try to read environment variables starting with "EMQX_"
  29. export HOCON_ENV_OVERRIDE_PREFIX='EMQX_'
  30. export ROOTDIR="$RUNNER_ROOT_DIR"
  31. export ERTS_DIR="$ROOTDIR/erts-$ERTS_VSN"
  32. export BINDIR="$ERTS_DIR/bin"
  33. export EMU="beam"
  34. export PROGNAME="erl"
  35. export ERTS_LIB_DIR="$ERTS_DIR/../lib"
  36. DYNLIBS_DIR="$RUNNER_ROOT_DIR/dynlibs"
  37. # Echo to stderr on errors
  38. echoerr() { echo "ERROR: $*" 1>&2; }
  39. die() {
  40. echoerr "ERROR: $1"
  41. errno=${2:-1}
  42. exit "$errno"
  43. }
  44. assert_node_alive() {
  45. if ! relx_nodetool "ping" > /dev/null; then
  46. die "node_is_not_running!" 1
  47. fi
  48. }
  49. # Echo to stderr on errors
  50. echoerr() { echo "$*" 1>&2; }
  51. check_erlang_start() {
  52. "$BINDIR/$PROGNAME" -noshell -boot "$REL_DIR/start_clean" -s crypto start -s erlang halt
  53. }
  54. usage() {
  55. local command="$1"
  56. case "$command" in
  57. start)
  58. echo "Start EMQ X service in daemon mode"
  59. ;;
  60. stop)
  61. echo "Stop the running EMQ X program"
  62. ;;
  63. restart|reboot)
  64. echo "Restart $EMQX_DESCRIPTION"
  65. ;;
  66. pid)
  67. echo "Print out $EMQX_DESCRIPTION process identifier"
  68. ;;
  69. ping)
  70. echo "Check if the $EMQX_DESCRIPTION node is up and running"
  71. echo "This command exit with 0 silently if node is running"
  72. ;;
  73. escript)
  74. echo "Execute a escript using the Erlang runtime from EMQ X package installation"
  75. echo "For example $REL_NAME escript /path/to/my/escript my_arg1 my_arg2"
  76. ;;
  77. attach)
  78. echo "This command is applicable when $EMQX_DESCRIPTION is started in daemon"
  79. echo "mode. it attaches the current shell to EMQ X's control console"
  80. echo "through a named pipe"
  81. echo "WARNING: try to use the safer alternative, remote_console command."
  82. ;;
  83. remote_console)
  84. echo "Start a dummy Erlang node and hidden-connect $EMQX_DESCRIPTION to"
  85. echo "with an interactive Erlang shell"
  86. ;;
  87. console)
  88. echo "Boot up $EMQX_DESCRIPTION service in an interactive Erlang shell"
  89. echo "This command is useful for troubleshooting"
  90. ;;
  91. console_clean)
  92. echo "This command does NOT boot up the $EMQX_DESCRIPTION service"
  93. echo "It only starts an interactive Erlang console with all the"
  94. echo "EMQ X code available"
  95. ;;
  96. foreground)
  97. echo "Start $EMQX_DESCRIPTION in foreground mode"
  98. ;;
  99. ertspath)
  100. echo "Print path to Erlang runtime dir"
  101. ;;
  102. rpc)
  103. echo "Usge $REL_NAME rpc MODULE FUNCTION [ARGS, ...]"
  104. echo "Connect to the $EMQX_DESCRIPTION node and make an Erlang RPC"
  105. echo "The result of the RPC call must be 'ok'"
  106. echo "This command blocks for at most 60 seconds in case the node"
  107. echo "does not reply the call in time"
  108. ;;
  109. rpcterms)
  110. echo "Usge $REL_NAME rpcterms MODULE FUNCTION [ARGS, ...]"
  111. echo "Connect to the $EMQX_DESCRIPTION node and make an Erlang RPC"
  112. echo "The result of the RPC call is pretty-printed as an Erlang term"
  113. ;;
  114. root_dir)
  115. echo "Print EMQ X installation root dir"
  116. ;;
  117. eval)
  118. echo "Evaluate an Erlang expression in the EMQ X node"
  119. ;;
  120. versions)
  121. echo "List installed EMQ X versions and their status"
  122. ;;
  123. unpack)
  124. echo "Usage: $REL_NAME unpack [VERSION]"
  125. echo "Unpacks a release package VERSION, it assumes that this"
  126. echo "release package tarball has already been deployed at one"
  127. echo "of the following locations:"
  128. echo " releases/<relname>-<version>.tar.gz"
  129. echo " releases/<relname>-<version>.zip"
  130. ;;
  131. install)
  132. echo "Usage: $REL_NAME install [VERSION]"
  133. echo "Installs a release package VERSION, it assumes that this"
  134. echo "release package tarball has already been deployed at one"
  135. echo "of the following locations:"
  136. echo " releases/<relname>-<version>.tar.gz"
  137. echo " releases/<relname>-<version>.zip"
  138. echo ""
  139. echo " --no-permanent Install release package VERSION but"
  140. echo " don't make it permanent"
  141. ;;
  142. uninstall)
  143. echo "Usage: $REL_NAME uninstall [VERSION]"
  144. echo "Uninstalls a release VERSION, it will only accept"
  145. echo "versions that are not currently in use"
  146. ;;
  147. upgrade)
  148. echo "Usage: $REL_NAME upgrade [VERSION]"
  149. echo "Upgrades the currently running release to VERSION, it assumes"
  150. echo "that a release package tarball has already been deployed at one"
  151. echo "of the following locations:"
  152. echo " releases/<relname>-<version>.tar.gz"
  153. echo " releases/<relname>-<version>.zip"
  154. echo ""
  155. echo " --no-permanent Install release package VERSION but"
  156. echo " don't make it permanent"
  157. ;;
  158. downgrade)
  159. echo "Usage: $REL_NAME downgrade [VERSION]"
  160. echo "Downgrades the currently running release to VERSION, it assumes"
  161. echo "that a release package tarball has already been deployed at one"
  162. echo "of the following locations:"
  163. echo " releases/<relname>-<version>.tar.gz"
  164. echo " releases/<relname>-<version>.zip"
  165. echo ""
  166. echo " --no-permanent Install release package VERSION but"
  167. echo " don't make it permanent"
  168. ;;
  169. *)
  170. 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>"
  171. ;;
  172. esac
  173. }
  174. COMMAND="${1:-}"
  175. if [ "${2:-}" = 'help' ]; then
  176. ## 'ctl' command has its own usage info
  177. if [ "$COMMAND" != 'ctl' ]; then
  178. usage "$COMMAND"
  179. exit 0
  180. fi
  181. fi
  182. if ! check_erlang_start >/dev/null 2>&1; then
  183. BUILT_ON="$(head -1 "${REL_DIR}/BUILT_ON")"
  184. ## failed to start, might be due to missing libs, try to be portable
  185. export LD_LIBRARY_PATH="$DYNLIBS_DIR:$LD_LIBRARY_PATH"
  186. if ! check_erlang_start; then
  187. ## it's hopeless
  188. echoerr "FATAL: Unable to start Erlang (with libcrypto)."
  189. echoerr "Please make sure it's running on the correct platform with all required dependencies."
  190. echoerr "This EMQ X release is built for $BUILT_ON"
  191. exit 1
  192. fi
  193. echoerr "WARNING: There seem to be missing dynamic libs from the OS. Using libs from ${DYNLIBS_DIR}"
  194. fi
  195. ## backward compatible
  196. if [ -d "$ERTS_DIR/lib" ]; then
  197. export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
  198. fi
  199. # Simple way to check the correct user and fail early
  200. check_user() {
  201. # Validate that the user running the script is the owner of the
  202. # RUN_DIR.
  203. if [ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]; then
  204. if [ "x$WHOAMI" != "xroot" ]; then
  205. echo "You need to be root or use sudo to run this command"
  206. exit 1
  207. fi
  208. CMD="DEBUG=$DEBUG \"$RUNNER_SCRIPT\" "
  209. for ARG in "$@"; do
  210. CMD="${CMD} \"$ARG\""
  211. done
  212. # This will drop priviledges into the runner user
  213. # It exec's in a new shell and the current shell will exit
  214. exec su - "$RUNNER_USER" -c "$CMD"
  215. fi
  216. }
  217. # Make sure the user running this script is the owner and/or su to that user
  218. check_user "$@"
  219. ES=$?
  220. if [ "$ES" -ne 0 ]; then
  221. exit $ES
  222. fi
  223. # EPMD_ARG="-start_epmd true $PROTO_DIST_ARG"
  224. NO_EPMD="-start_epmd false -epmd_module ekka_epmd -proto_dist ekka"
  225. EPMD_ARG="${EPMD_ARG:-${NO_EPMD}}"
  226. # Warn the user if ulimit -n is less than 1024
  227. ULIMIT_F=$(ulimit -n)
  228. if [ "$ULIMIT_F" -lt 1024 ]; then
  229. echo "!!!!"
  230. echo "!!!! WARNING: ulimit -n is ${ULIMIT_F}; 1024 is the recommended minimum."
  231. echo "!!!!"
  232. fi
  233. SED_REPLACE="sed -i "
  234. case $(sed --help 2>&1) in
  235. *GNU*) SED_REPLACE="sed -i ";;
  236. *BusyBox*) SED_REPLACE="sed -i ";;
  237. *) SED_REPLACE="sed -i '' ";;
  238. esac
  239. # Get node pid
  240. relx_get_pid() {
  241. if output="$(relx_nodetool rpcterms os getpid)"
  242. then
  243. # shellcheck disable=SC2001 # Escaped quote taken as closing quote in editor
  244. echo "$output" | sed -e 's/"//g'
  245. return 0
  246. else
  247. echo "$output"
  248. return 1
  249. fi
  250. }
  251. # Connect to a remote node
  252. relx_rem_sh() {
  253. # Generate a unique id used to allow multiple remsh to the same node
  254. # transparently
  255. id="remsh$(relx_gen_id)-${NAME}"
  256. # Get the node's ticktime so that we use the same thing.
  257. TICKTIME="$(relx_nodetool rpcterms net_kernel get_net_ticktime)"
  258. # shellcheck disable=SC2086 # $EPMD_ARG is supposed to be split by whitespace
  259. # Setup remote shell command to control node
  260. exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot "$REL_DIR/start_clean" \
  261. -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
  262. -setcookie "$COOKIE" -hidden -kernel net_ticktime "$TICKTIME" $EPMD_ARG
  263. }
  264. # Generate a random id
  265. relx_gen_id() {
  266. od -t x -N 4 /dev/urandom | head -n1 | awk '{print $2}'
  267. }
  268. # Control a node
  269. relx_nodetool() {
  270. command="$1"; shift
  271. ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
  272. "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \
  273. -setcookie "$COOKIE" "$command" "$@"
  274. }
  275. call_hocon() {
  276. "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" hocon "$@" \
  277. || die "call_hocon_failed: $*" $?
  278. }
  279. # Run an escript in the node's environment
  280. relx_escript() {
  281. shift; scriptpath="$1"; shift
  282. "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" "$@"
  283. }
  284. # Output a start command for the last argument of run_erl
  285. relx_start_command() {
  286. printf "exec \"%s\" \"%s\"" "$RUNNER_SCRIPT" \
  287. "$START_OPTION"
  288. }
  289. # Function to generate app.config and vm.args
  290. generate_config() {
  291. local name_type="$1"
  292. local node_name="$2"
  293. ## Delete the *.siz files first or it cann't start after
  294. ## changing the config 'log.rotation.size'
  295. rm -rf "${RUNNER_LOG_DIR}"/*.siz
  296. EMQX_LICENSE_CONF_OPTION=""
  297. if [ "${EMQX_LICENSE_CONF:-}" != "" ]; then
  298. EMQX_LICENSE_CONF_OPTION="-c ${EMQX_LICENSE_CONF}"
  299. fi
  300. ## timestamp for each generation
  301. local NOW_TIME
  302. NOW_TIME="$(call_hocon now_time)"
  303. ## ths command populates two files: app.<time>.config and vm.<time>.args
  304. ## disable SC2086 to allow EMQX_LICENSE_CONF_OPTION to split
  305. # shellcheck disable=SC2086
  306. call_hocon -v -t "$NOW_TIME" -I "$CONFIGS_DIR/" -s $SCHEMA_MOD -c "$RUNNER_ETC_DIR"/emqx.conf $EMQX_LICENSE_CONF_OPTION -d "$RUNNER_DATA_DIR"/configs generate
  307. ## filenames are per-hocon convention
  308. local CONF_FILE="$CONFIGS_DIR/app.$NOW_TIME.config"
  309. local HOCON_GEN_ARG_FILE="$CONFIGS_DIR/vm.$NOW_TIME.args"
  310. CONFIG_ARGS="-config $CONF_FILE -args_file $HOCON_GEN_ARG_FILE"
  311. ## Merge hocon generated *.args into the vm.args
  312. TMP_ARG_FILE="$CONFIGS_DIR/vm.args.tmp"
  313. cp "$RUNNER_ETC_DIR/vm.args" "$TMP_ARG_FILE"
  314. echo "" >> "$TMP_ARG_FILE"
  315. echo "-pa ${REL_DIR}/consolidated" >> "$TMP_ARG_FILE"
  316. ## read lines from generated vm.<time>.args file
  317. ## drop comment lines, and empty lines using sed
  318. ## pipe the lines to a while loop
  319. sed '/^#/d' "$HOCON_GEN_ARG_FILE" | sed '/^$/d' | while IFS='' read -r ARG_LINE || [ -n "$ARG_LINE" ]; do
  320. ## in the loop, split the 'key[:space:]value' pair
  321. ARG_KEY=$(echo "$ARG_LINE" | awk '{$NF="";print}')
  322. ARG_VALUE=$(echo "$ARG_LINE" | awk '{print $NF}')
  323. ## use the key to look up in vm.args file for the value
  324. TMP_ARG_VALUE=$(grep "^$ARG_KEY" "$TMP_ARG_FILE" || true | awk '{print $NF}')
  325. ## compare generated (to override) value to original (to be overriden) value
  326. if [ "$ARG_VALUE" != "$TMP_ARG_VALUE" ] ; then
  327. ## if they are different
  328. if [ -n "$TMP_ARG_VALUE" ]; then
  329. ## if the old value is present, replace it with generated value
  330. sh -c "$SED_REPLACE 's|^$ARG_KEY.*$|$ARG_LINE|' $TMP_ARG_FILE"
  331. else
  332. ## otherwise append generated value to the end
  333. echo "$ARG_LINE" >> "$TMP_ARG_FILE"
  334. fi
  335. fi
  336. done
  337. echo "$name_type $node_name" >> "$TMP_ARG_FILE"
  338. ## rename the generated vm.<time>.args file
  339. mv -f "$TMP_ARG_FILE" "$HOCON_GEN_ARG_FILE"
  340. # shellcheck disable=SC2086
  341. if ! relx_nodetool chkconfig $CONFIG_ARGS; then
  342. die "failed_to_check_config $CONFIG_ARGS"
  343. fi
  344. }
  345. # check if a PID is down
  346. is_down() {
  347. PID="$1"
  348. if ps -p "$PID" >/dev/null; then
  349. # still around
  350. # shellcheck disable=SC2009 # this grep pattern is not a part of the progra names
  351. if ps -p "$PID" | grep -q 'defunct'; then
  352. # zombie state, print parent pid
  353. parent="$(ps -o ppid= -p "$PID" | tr -d ' ')"
  354. echo "WARN: $PID is marked <defunct>, parent:"
  355. ps -p "$parent"
  356. return 0
  357. fi
  358. return 1
  359. fi
  360. # it's gone
  361. return 0
  362. }
  363. wait_for() {
  364. local WAIT_TIME
  365. local CMD
  366. WAIT_TIME="$1"
  367. shift
  368. CMD="$*"
  369. while true; do
  370. if $CMD >/dev/null 2>&1; then
  371. return 0
  372. fi
  373. if [ "$WAIT_TIME" -le 0 ]; then
  374. return 1
  375. fi
  376. WAIT_TIME=$((WAIT_TIME - 1))
  377. sleep 1
  378. done
  379. }
  380. latest_vm_args() {
  381. local hint_var_name="$1"
  382. local vm_args_file
  383. vm_args_file="$(find "$CONFIGS_DIR" -type f -name "vm.*.args" | sort | tail -1)"
  384. if [ -f "$vm_args_file" ]; then
  385. echo "$vm_args_file"
  386. else
  387. echoerr "ERRRO: node not initialized?"
  388. echoerr "Generated config file vm.*.args is not found for command '$COMMAND'"
  389. echoerr "in config dir: $CONFIGS_DIR"
  390. echoerr "In case the file has been deleted while the node is running,"
  391. echoerr "set environment variable '$hint_var_name' to continue"
  392. exit 1
  393. fi
  394. }
  395. ## IS_BOOT_COMMAND is set for later to inspect node name and cookie from hocon config (or env variable)
  396. case "${COMMAND}" in
  397. start|console|console_clean|foreground)
  398. IS_BOOT_COMMAND='yes'
  399. ;;
  400. *)
  401. IS_BOOT_COMMAND='no'
  402. ;;
  403. esac
  404. ## Possible ways to configure emqx node name:
  405. ## 1. configure node.name in emqx.conf
  406. ## 2. override with environment variable EMQX_NODE_NAME
  407. ## Node name is either short-name (without '@'), e.g. 'emqx'
  408. ## or long name (with '@') e.g. 'emqx@example.net' or 'emqx@127.0.0.1'
  409. NAME="${EMQX_NODE_NAME:-}"
  410. if [ -z "$NAME" ]; then
  411. if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
  412. # for boot commands, inspect emqx.conf for node name
  413. NAME="$(call_hocon -s $SCHEMA_MOD -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get node.name | tr -d \")"
  414. else
  415. vm_args_file="$(latest_vm_args 'EMQX_NODE_NAME')"
  416. NAME="$(grep -E '^-s?name' "${vm_args_file}" | awk '{print $2}')"
  417. fi
  418. fi
  419. # force to use 'emqx' short name
  420. [ -z "$NAME" ] && NAME='emqx'
  421. MNESIA_DATA_DIR="$RUNNER_DATA_DIR/mnesia/$NAME"
  422. case "$NAME" in
  423. *@*)
  424. NAME_TYPE='-name'
  425. ;;
  426. *)
  427. NAME_TYPE='-sname'
  428. esac
  429. SHORT_NAME="$(echo "$NAME" | awk -F'@' '{print $1}')"
  430. export ESCRIPT_NAME="$SHORT_NAME"
  431. PIPE_DIR="${PIPE_DIR:-/$RUNNER_DATA_DIR/${WHOAMI}_erl_pipes/$NAME/}"
  432. COOKIE="${EMQX_NODE_COOKIE:-}"
  433. if [ -z "$COOKIE" ]; then
  434. if [ "$IS_BOOT_COMMAND" = 'yes' ]; then
  435. COOKIE="$(call_hocon -s $SCHEMA_MOD -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get node.cookie | tr -d \")"
  436. else
  437. vm_args_file="$(latest_vm_args 'EMQX_NODE_COOKIE')"
  438. COOKIE="$(grep -E '^-setcookie' "${vm_args_file}" | awk '{print $2}')"
  439. fi
  440. fi
  441. if [ -z "$COOKIE" ]; then
  442. die "Please set node.cookie in $RUNNER_ETC_DIR/emqx.conf or override from environment variable EMQX_NODE_COOKIE"
  443. fi
  444. cd "$ROOTDIR"
  445. case "${COMMAND}" in
  446. start)
  447. # Make sure a node IS not running
  448. if relx_nodetool "ping" >/dev/null 2>&1; then
  449. die "node_is_already_running!"
  450. fi
  451. # this flag passes down to console mode
  452. # so we know it's intended to be run in daemon mode
  453. export _EMQX_START_MODE="$COMMAND"
  454. case "$COMMAND" in
  455. start)
  456. shift
  457. START_OPTION="console"
  458. HEART_OPTION="start"
  459. ;;
  460. esac
  461. RUN_PARAM="$*"
  462. # Set arguments for the heart command
  463. set -- "$RUNNER_SCRIPT" "$HEART_OPTION"
  464. [ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM"
  465. # Export the HEART_COMMAND
  466. HEART_COMMAND="$RUNNER_SCRIPT $COMMAND"
  467. export HEART_COMMAND
  468. ## See: http://erlang.org/doc/man/run_erl.html
  469. # Export the RUN_ERL_LOG_GENERATIONS
  470. export RUN_ERL_LOG_GENERATIONS=${RUN_ERL_LOG_GENERATIONS:-"5"}
  471. # Export the RUN_ERL_LOG_MAXSIZE
  472. export RUN_ERL_LOG_MAXSIZE=${RUN_ERL_LOG_MAXSIZE:-"10485760"}
  473. mkdir -p "$PIPE_DIR"
  474. "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \
  475. "$(relx_start_command)"
  476. WAIT_TIME=${WAIT_FOR_ERLANG:-15}
  477. if wait_for "$WAIT_TIME" 'relx_nodetool' 'ping'; then
  478. echo "$EMQX_DESCRIPTION $REL_VSN is started successfully!"
  479. exit 0
  480. else
  481. echo "$EMQX_DESCRIPTION $REL_VSN failed to start within ${WAIT_TIME} seconds,"
  482. echo "see the output of '$0 console' for more information."
  483. echo "If you want to wait longer, set the environment variable"
  484. echo "WAIT_FOR_ERLANG to the number of seconds to wait."
  485. exit 1
  486. fi
  487. ;;
  488. stop)
  489. # Wait for the node to completely stop...
  490. PID="$(relx_get_pid)"
  491. if ! relx_nodetool "stop"; then
  492. echoerr "Graceful shutdown failed PID=[$PID]"
  493. exit 1
  494. fi
  495. WAIT_TIME="${WAIT_FOR_ERLANG_STOP:-60}"
  496. if ! wait_for "$WAIT_TIME" 'is_down' "$PID"; then
  497. msg="dangling after ${WAIT_TIME} seconds"
  498. # also log to syslog
  499. logger -t "${REL_NAME}[${PID}]" "STOP: $msg"
  500. # log to user console
  501. echoerr "stop failed, $msg"
  502. echo "ERROR: $PID is still around"
  503. ps -p "$PID"
  504. exit 1
  505. fi
  506. logger -t "${REL_NAME}[${PID}]" "STOP: OK"
  507. ;;
  508. restart|reboot)
  509. echo "$EMQX_DESCRIPTION $REL_VSN is stopped: $("$RUNNER_BIN_DIR/$REL_NAME" stop)"
  510. "$RUNNER_BIN_DIR/$REL_NAME" start
  511. ;;
  512. pid)
  513. ## Get the VM's pid
  514. if ! relx_get_pid; then
  515. exit 1
  516. fi
  517. ;;
  518. ping)
  519. assert_node_alive
  520. ;;
  521. escript)
  522. ## Run an escript under the node's environment
  523. if ! relx_escript "$@"; then
  524. exit 1
  525. fi
  526. ;;
  527. attach)
  528. assert_node_alive
  529. shift
  530. exec "$BINDIR/to_erl" "$PIPE_DIR"
  531. ;;
  532. remote_console)
  533. assert_node_alive
  534. shift
  535. relx_rem_sh
  536. ;;
  537. upgrade|downgrade|install|unpack|uninstall)
  538. if [ -z "${2:-}" ]; then
  539. echo "Missing version argument"
  540. echo "Usage: $REL_NAME $COMMAND {version}"
  541. exit 1
  542. fi
  543. shift
  544. assert_node_alive
  545. ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
  546. exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
  547. "$COMMAND" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@"
  548. ;;
  549. versions)
  550. assert_node_alive
  551. shift
  552. ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \
  553. exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
  554. "versions" "{'$REL_NAME', \"$NAME_TYPE\", '$NAME', '$COOKIE'}" "$@"
  555. ;;
  556. console|console_clean)
  557. # .boot file typically just $REL_NAME (ie, the app name)
  558. # however, for debugging, sometimes start_clean.boot is useful.
  559. # For e.g. 'setup', one may even want to name another boot script.
  560. case "$COMMAND" in
  561. console)
  562. if [ -f "$REL_DIR/$REL_NAME.boot" ]; then
  563. BOOTFILE="$REL_DIR/$REL_NAME"
  564. else
  565. BOOTFILE="$REL_DIR/start"
  566. fi
  567. ;;
  568. console_clean)
  569. BOOTFILE="$REL_DIR/start_clean"
  570. ;;
  571. esac
  572. # set before generate_config
  573. if [ "${_EMQX_START_MODE:-}" = '' ]; then
  574. export EMQX_LOG__CONSOLE_HANDLER__ENABLE="${EMQX_LOG__CONSOLE_HANDLER__ENABLE:-true}"
  575. fi
  576. #generate app.config and vm.args
  577. generate_config "$NAME_TYPE" "$NAME"
  578. # Setup beam-required vars
  579. EMU="beam"
  580. PROGNAME="${0#*/}"
  581. export EMU
  582. export PROGNAME
  583. # Store passed arguments since they will be erased by `set`
  584. ARGS="$*"
  585. # shellcheck disable=SC2086 # $CONFIG_ARGS $EPMD_ARG are supposed to be split by whitespace
  586. # Build an array of arguments to pass to exec later on
  587. # Build it here because this command will be used for logging.
  588. set -- "$BINDIR/erlexec" \
  589. -boot "$BOOTFILE" -mode "$CODE_LOADING_MODE" \
  590. -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
  591. -mnesia dir "\"${MNESIA_DATA_DIR}\"" \
  592. $CONFIG_ARGS $EPMD_ARG
  593. # Log the startup
  594. logger -t "${REL_NAME}[$$]" "EXEC: $* -- ${1+$ARGS}"
  595. # Start the VM
  596. exec "$@" -- ${1+$ARGS}
  597. ;;
  598. foreground)
  599. # start up the release in the foreground for use by runit
  600. # or other supervision services
  601. # set before generate_config
  602. export EMQX_LOG__CONSOLE_HANDLER__ENABLE="${EMQX_LOG__CONSOLE_HANDLER__ENABLE:-true}"
  603. #generate app.config and vm.args
  604. generate_config "$NAME_TYPE" "$NAME"
  605. [ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start
  606. FOREGROUNDOPTIONS="-noshell -noinput +Bd"
  607. # Setup beam-required vars
  608. EMU=beam
  609. PROGNAME="${0#*/}"
  610. export EMU
  611. export PROGNAME
  612. # Store passed arguments since they will be erased by `set`
  613. ARGS="$*"
  614. # shellcheck disable=SC2086 # $CONFIG_ARGS $EPMD_ARG are supposed to be split by whitespace
  615. # Build an array of arguments to pass to exec later on
  616. # Build it here because this command will be used for logging.
  617. set -- "$BINDIR/erlexec" $FOREGROUNDOPTIONS \
  618. -boot "$REL_DIR/$BOOTFILE" -mode "$CODE_LOADING_MODE" \
  619. -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
  620. -mnesia dir "\"${MNESIA_DATA_DIR}\"" \
  621. $CONFIG_ARGS $EPMD_ARG
  622. # Log the startup
  623. logger -t "${REL_NAME}[$$]" "EXEC: $* -- ${1+$ARGS}"
  624. # Start the VM
  625. exec "$@" -- ${1+$ARGS}
  626. ;;
  627. ertspath)
  628. echo "$ERTS_PATH"
  629. ;;
  630. ctl)
  631. assert_node_alive
  632. shift
  633. relx_nodetool rpc_infinity emqx_ctl run_command "$@"
  634. ;;
  635. rpc)
  636. assert_node_alive
  637. shift
  638. relx_nodetool rpc "$@"
  639. ;;
  640. rpcterms)
  641. assert_node_alive
  642. shift
  643. relx_nodetool rpcterms "$@"
  644. ;;
  645. root_dir)
  646. assert_node_alive
  647. shift
  648. relx_nodetool "eval" 'code:root_dir()'
  649. ;;
  650. eval)
  651. assert_node_alive
  652. shift
  653. relx_nodetool "eval" "$@"
  654. ;;
  655. *)
  656. usage "$COMMAND"
  657. exit 1
  658. ;;
  659. esac
  660. exit 0