emqx 27 KB

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