dev 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250
  1. #!/usr/bin/env bash
  2. set -euo pipefail
  3. usage() {
  4. cat <<EOF
  5. Run EMQX without building a release (which takes longer time).
  6. USAGE: $0 [OPTION]
  7. OPTIONS:
  8. -h Print this help usage info.
  9. -p 'emqx' or 'emqx-enterprise', defaults to 'PROFILE' env.
  10. -c Force recompile, otherwise starts with the already built libs
  11. in '_build/\$PROFILE/lib/'.
  12. ENVIRONMENT VARIABLES:
  13. PROFILE: Overriden by -p option, defaults to 'emqx'.
  14. EMQX_NODE_NAME: The node name of the EMQX node. Default to emqx@127.0.0.1'.
  15. EOF
  16. }
  17. if [ -n "${DEBUG:-}" ]; then
  18. set -x
  19. fi
  20. export HOCON_ENV_OVERRIDE_PREFIX='EMQX_'
  21. EMQX_NODE_NAME="${EMQX_NODE_NAME:-emqx@127.0.0.1}"
  22. PROFILE="${PROFILE:-emqx}"
  23. FORCE_COMPILE=0
  24. while getopts ":p:ch" opt; do
  25. case "${opt}" in
  26. h)
  27. usage
  28. exit 0
  29. ;;
  30. p)
  31. PROFILE="${OPTARG}"
  32. ;;
  33. c)
  34. FORCE_COMPILE=1
  35. ;;
  36. \?)
  37. echo "Invalid option: -$OPTARG" >&2
  38. exit 1
  39. ;;
  40. :)
  41. echo "Option -$OPTARG requires an argument." >&2
  42. exit 1
  43. ;;
  44. esac
  45. done
  46. shift $((OPTIND-1))
  47. case "${PROFILE}" in
  48. ce|emqx)
  49. PROFILE='emqx'
  50. ;;
  51. ee|emqx-enterprise)
  52. PROFILE='emqx-enterprise'
  53. ;;
  54. *)
  55. echo "Unknown profile $PROFILE"
  56. exit 1
  57. ;;
  58. esac
  59. export PROFILE
  60. case "${PROFILE}" in
  61. emqx)
  62. SCHEMA_MOD='emqx_conf_schema'
  63. ;;
  64. emqx-enterprise)
  65. SCHEMA_MOD='emqx_ee_conf_schema'
  66. ;;
  67. esac
  68. PROJ_ROOT="$(git rev-parse --show-toplevel)"
  69. cd "$PROJ_ROOT"
  70. BASE_DIR="_build/dev-run/$PROFILE"
  71. export EMQX_ETC_DIR="$BASE_DIR/etc"
  72. export EMQX_DATA_DIR="$BASE_DIR/data"
  73. export EMQX_LOG_DIR="$BASE_DIR/log"
  74. CONFIGS_DIR="$EMQX_DATA_DIR/configs"
  75. COOKIE='emqxsecretcookie'
  76. mkdir -p "$EMQX_ETC_DIR" "$EMQX_DATA_DIR/patches" "$EMQX_LOG_DIR" "$CONFIGS_DIR"
  77. ## build compile the profile is it's not compiled yet
  78. prepare_erl_libs() {
  79. local profile="$1"
  80. local libs_dir="_build/${profile}/lib"
  81. local erl_libs=''
  82. if [ $FORCE_COMPILE -eq 1 ] || [ ! -d "$libs_dir" ]; then
  83. make "compile-${PROFILE}"
  84. else
  85. echo "Running from code in $libs_dir"
  86. fi
  87. for app in "${libs_dir}"/*; do
  88. erl_libs="${erl_libs}:${app}"
  89. done
  90. export ERL_LIBS="$erl_libs"
  91. }
  92. ## poorman's mustache templating
  93. mustache() {
  94. local name="$1"
  95. local value="$2"
  96. local file="$3"
  97. sed -i "s|{{\s*${name}\s*}}|${value}|g" "$file"
  98. }
  99. ## render the merged boot conf file.
  100. ## the merge action is done before the profile is compiled
  101. render_hocon_conf() {
  102. input="apps/emqx_conf/etc/emqx.conf.all"
  103. output="$EMQX_ETC_DIR/emqx.conf"
  104. cp "$input" "$output"
  105. mustache emqx_default_erlang_cookie "$COOKIE" "$output"
  106. mustache platform_data_dir "${EMQX_DATA_DIR}" "$output"
  107. mustache platform_log_dir "${EMQX_LOG_DIR}" "$output"
  108. mustache platform_etc_dir "${EMQX_ETC_DIR}" "$output"
  109. }
  110. call_hocon() {
  111. local in=("$@")
  112. local args=''
  113. for arg in "${in[@]}"; do
  114. if [ -z "$args" ]; then
  115. args="\"$arg\""
  116. else
  117. args="$args, \"$arg\""
  118. fi
  119. done
  120. erl -noshell -eval "{ok, _} = application:ensure_all_started(hocon), ok = hocon_cli:main([$args]), init:stop()."
  121. }
  122. # Function to generate app.config and vm.args
  123. # sets two environment variables CONF_FILE and ARGS_FILE
  124. generate_app_conf() {
  125. ## timestamp for each generation
  126. local NOW_TIME
  127. NOW_TIME="$(date +'%Y.%m.%d.%H.%M.%S')"
  128. ## this command populates two files: app.<time>.config and vm.<time>.args
  129. ## NOTE: the generate command merges environment variables to the base config (emqx.conf),
  130. ## but does not include the cluster-override.conf and local-override.conf
  131. ## meaning, certain overrides will not be mapped to app.<time>.config file
  132. call_hocon -v -t "$NOW_TIME" -s "$SCHEMA_MOD" -c "$EMQX_ETC_DIR"/emqx.conf -d "$EMQX_DATA_DIR"/configs generate
  133. ## filenames are per-hocon convention
  134. CONF_FILE="$CONFIGS_DIR/app.$NOW_TIME.config"
  135. ARGS_FILE="$CONFIGS_DIR/vm.$NOW_TIME.args"
  136. }
  137. # apps/emqx/etc/vm.args.cloud
  138. append_args_file() {
  139. ## ensure a new line at the end
  140. echo '' >> "$ARGS_FILE"
  141. cat <<EOF >> "$ARGS_FILE"
  142. -name $EMQX_NODE_NAME
  143. -mnesia dir '"$EMQX_DATA_DIR/mnesia/$EMQX_NODE_NAME"'
  144. -stdlib restricted_shell emqx_restricted_shell
  145. +spp true
  146. +A 4
  147. +IOt 4
  148. +SDio 8
  149. -shutdown_time 30000
  150. -pa '"$EMQX_DATA_DIR/patches"'
  151. -mnesia dump_log_write_threshold 5000
  152. -mnesia dump_log_time_threshold 60000
  153. -os_mon start_disksup false
  154. EOF
  155. }
  156. # copy cert files and acl.conf to etc
  157. copy_other_conf_files() {
  158. cp -r apps/emqx/etc/certs "$EMQX_ETC_DIR"/
  159. cp apps/emqx_authz/etc/acl.conf "$EMQX_ETC_DIR"/
  160. }
  161. is_current_profile_app() {
  162. local app="$1"
  163. case "$app" in
  164. lib-ee*)
  165. if [ "$PROFILE" = 'emqx-enterprise' ]; then
  166. return 0
  167. else
  168. return 1
  169. fi
  170. ;;
  171. *)
  172. if [ "$PROFILE" = 'emqx' ]; then
  173. if [ -f "$app"/BSL.txt ]; then
  174. return 1
  175. else
  176. return 0
  177. fi
  178. else
  179. return 0
  180. fi
  181. ;;
  182. esac
  183. }
  184. ## apps to load
  185. apps_to_load() {
  186. local apps csl
  187. apps="$(./scripts/find-apps.sh | xargs)"
  188. csl=""
  189. for app in $apps; do
  190. if ! is_current_profile_app "$app"; then
  191. continue
  192. fi
  193. name="$(basename "$app")"
  194. if [ -z "$csl" ]; then
  195. csl="$name"
  196. else
  197. csl="$csl,$name"
  198. fi
  199. done
  200. echo "$csl"
  201. }
  202. ## Make erl command aware where to load all the beams
  203. ## this should be done before every erl command
  204. prepare_erl_libs "$PROFILE"
  205. render_hocon_conf
  206. generate_app_conf
  207. append_args_file
  208. copy_other_conf_files
  209. APPS="$(apps_to_load)"
  210. BOOT_SEQUENCE="
  211. Apps=[${APPS}],
  212. ok=lists:foreach(fun application:load/1, Apps),
  213. io:format(user, \"~nLoaded ~p apps~n\", [length(Apps)]),
  214. application:ensure_all_started(emqx_machine).
  215. "
  216. erl -name "$EMQX_NODE_NAME" \
  217. -start_epmd false \
  218. -epmd_module ekka_epmd \
  219. -proto_dist ekka \
  220. -args_file "$ARGS_FILE" \
  221. -config "$CONF_FILE" \
  222. -s emqx_restricted_shell set_prompt_func \
  223. -eval "$BOOT_SEQUENCE"