diff --git a/bin/common_defs.sh b/bin/common_defs.sh new file mode 100644 index 000000000..45d35eeb4 --- /dev/null +++ b/bin/common_defs.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +DEBUG="${DEBUG:-0}" +if [ "$DEBUG" -eq 1 ]; then + set -x +fi + +ROOT_DIR="$(cd "$(dirname "$(readlink "$0" || echo "$0")")"/..; pwd -P)" +# shellcheck disable=SC1090 +. "$ROOT_DIR"/releases/emqx_vars + +# defined in emqx_vars +export RUNNER_ROOT_DIR +export RUNNER_ETC_DIR +export REL_VSN + +RUNNER_SCRIPT="$RUNNER_BIN_DIR/$REL_NAME" +CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}" +REL_DIR="$RUNNER_ROOT_DIR/releases/$REL_VSN" +SCHEMA_MOD=emqx_conf_schema + +WHOAMI=$(whoami) + +# Make sure data/configs exists +CONFIGS_DIR="$RUNNER_DATA_DIR/configs" + +# hocon try to read environment variables starting with "EMQX_" +export HOCON_ENV_OVERRIDE_PREFIX='EMQX_' + +export ROOTDIR="$RUNNER_ROOT_DIR" +export ERTS_DIR="$ROOTDIR/erts-$ERTS_VSN" +export BINDIR="$ERTS_DIR/bin" +export EMU="beam" +export PROGNAME="erl" +export ERTS_LIB_DIR="$ERTS_DIR/../lib" +DYNLIBS_DIR="$RUNNER_ROOT_DIR/dynlibs" + +## backward compatible +if [ -d "$ERTS_DIR/lib" ]; then + export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH" +fi + +# EPMD_ARG="-start_epmd true $PROTO_DIST_ARG" +NO_EPMD="-start_epmd false -epmd_module ekka_epmd -proto_dist ekka" +EPMD_ARG="${EPMD_ARG:-${NO_EPMD}}" + +# Warn the user if ulimit -n is less than 1024 +ULIMIT_F=$(ulimit -n) +if [ "$ULIMIT_F" -lt 1024 ]; then + echo "!!!!" + echo "!!!! WARNING: ulimit -n is ${ULIMIT_F}; 1024 is the recommended minimum." + echo "!!!!" +fi + +SED_REPLACE="sed -i " +case $(sed --help 2>&1) in + *GNU*) SED_REPLACE="sed -i ";; + *BusyBox*) SED_REPLACE="sed -i ";; + *) SED_REPLACE="sed -i '' ";; +esac diff --git a/bin/common_defs2.sh b/bin/common_defs2.sh new file mode 100644 index 000000000..f699add3c --- /dev/null +++ b/bin/common_defs2.sh @@ -0,0 +1,65 @@ +#!/bin/bash + +## NOTE: those are defined separately from `common_defs.sh` because +## they require `common_functions.sh` to be sourced prior to sourcing +## this file. Basically, the definitions below depend on the function +## `call_hocon`, which is defined in `common_functions.sh`. Also, +## they require the variable `IS_BOOT_COMMAND` to be set to either +## `yes` or `no` for the name definition to be done properly. + +## make EMQX_NODE_COOKIE right +if [ -n "${EMQX_NODE_NAME:-}" ]; then + export EMQX_NODE__NAME="${EMQX_NODE_NAME}" + unset EMQX_NODE_NAME +fi + +## Possible ways to configure emqx node name: +## 1. configure node.name in emqx.conf +## 2. override with environment variable EMQX_NODE__NAME +## Node name is either short-name (without '@'), e.g. 'emqx' +## or long name (with '@') e.g. 'emqx@example.net' or 'emqx@127.0.0.1' +NAME="${EMQX_NODE__NAME:-}" +if [ -z "$NAME" ]; then + if [ "$IS_BOOT_COMMAND" = 'yes' ]; then + # for boot commands, inspect emqx.conf for node name + NAME="$(call_hocon -s $SCHEMA_MOD -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get node.name | tr -d \")" + else + vm_args_file="$(latest_vm_args 'EMQX_NODE__NAME')" + NAME="$(grep -E '^-s?name' "${vm_args_file}" | awk '{print $2}')" + fi +fi + +# force to use 'emqx' short name +[ -z "$NAME" ] && NAME='emqx' +MNESIA_DATA_DIR="$RUNNER_DATA_DIR/mnesia/$NAME" + +case "$NAME" in + *@*) + NAME_TYPE='-name' + ;; + *) + NAME_TYPE='-sname' +esac +SHORT_NAME="$(echo "$NAME" | awk -F'@' '{print $1}')" +export ESCRIPT_NAME="$SHORT_NAME" + +PIPE_DIR="${PIPE_DIR:-/$RUNNER_DATA_DIR/${WHOAMI}_erl_pipes/$NAME/}" + +## make EMQX_NODE_COOKIE right +if [ -n "${EMQX_NODE_COOKIE:-}" ]; then + export EMQX_NODE__COOKIE="${EMQX_NODE_COOKIE}" + unset EMQX_NODE_COOKIE +fi +COOKIE="${EMQX_NODE__COOKIE:-}" +if [ -z "$COOKIE" ]; then + if [ "$IS_BOOT_COMMAND" = 'yes' ]; then + COOKIE="$(call_hocon -s $SCHEMA_MOD -I "$CONFIGS_DIR/" -c "$RUNNER_ETC_DIR"/emqx.conf get node.cookie | tr -d \")" + else + vm_args_file="$(latest_vm_args 'EMQX_NODE__COOKIE')" + COOKIE="$(grep -E '^-setcookie' "${vm_args_file}" | awk '{print $2}')" + fi +fi + +if [ -z "$COOKIE" ]; then + die "Please set node.cookie in $RUNNER_ETC_DIR/emqx.conf or override from environment variable EMQX_NODE__COOKIE" +fi diff --git a/bin/common_functions.sh b/bin/common_functions.sh new file mode 100644 index 000000000..cff9ed76a --- /dev/null +++ b/bin/common_functions.sh @@ -0,0 +1,217 @@ +#!/bin/bash + +# Echo to stderr on errors +echoerr() { echo "ERROR: $*" 1>&2; } + +die() { + echoerr "ERROR: $1" + errno=${2:-1} + exit "$errno" +} + +assert_node_alive() { + if ! relx_nodetool "ping" > /dev/null; then + die "node_is_not_running!" 1 + fi +} + +check_erlang_start() { + "$BINDIR/$PROGNAME" -noshell -boot "$REL_DIR/start_clean" -s crypto start -s erlang halt +} + +# Simple way to check the correct user and fail early +check_user() { + # Validate that the user running the script is the owner of the + # RUN_DIR. + if [ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]; then + if [ "x$WHOAMI" != "xroot" ]; then + echo "You need to be root or use sudo to run this command" + exit 1 + fi + CMD="DEBUG=$DEBUG \"$RUNNER_SCRIPT\" " + for ARG in "$@"; do + CMD="${CMD} \"$ARG\"" + done + # This will drop priviledges into the runner user + # It exec's in a new shell and the current shell will exit + exec su - "$RUNNER_USER" -c "$CMD" + fi +} + +# Get node pid +relx_get_pid() { + if output="$(relx_nodetool rpcterms os getpid)" + then + # shellcheck disable=SC2001 # Escaped quote taken as closing quote in editor + echo "$output" | sed -e 's/"//g' + return 0 + else + echo "$output" + return 1 + fi +} + +# Connect to a remote node +relx_rem_sh() { + # Generate a unique id used to allow multiple remsh to the same node + # transparently + id="remsh$(relx_gen_id)-${NAME}" + # Get the node's ticktime so that we use the same thing. + TICKTIME="$(relx_nodetool rpcterms net_kernel get_net_ticktime)" + + # shellcheck disable=SC2086 # $EPMD_ARG is supposed to be split by whitespace + # Setup remote shell command to control node + exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot "$REL_DIR/start_clean" \ + -boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \ + -setcookie "$COOKIE" -hidden -kernel net_ticktime "$TICKTIME" $EPMD_ARG +} + +# Generate a random id +relx_gen_id() { + od -t x -N 4 /dev/urandom | head -n1 | awk '{print $2}' +} + +# Control a node +relx_nodetool() { + command="$1"; shift + ERL_FLAGS="${ERL_FLAGS:-} $EPMD_ARG" \ + "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ + -setcookie "$COOKIE" "$command" "$@" +} + +call_hocon() { + "$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" hocon "$@" \ + || die "call_hocon_failed: $*" $? +} + +# Run an escript in the node's environment +relx_escript() { + shift; scriptpath="$1"; shift + "$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" "$@" +} + +# Output a start command for the last argument of run_erl +relx_start_command() { + printf "exec \"%s\" \"%s\"" "$RUNNER_SCRIPT" \ + "$START_OPTION" +} + +# Function to generate app.config and vm.args +generate_config() { + local name_type="$1" + local node_name="$2" + ## Delete the *.siz files first or it cann't start after + ## changing the config 'log.rotation.size' + rm -rf "${RUNNER_LOG_DIR}"/*.siz + + EMQX_LICENSE_CONF_OPTION="" + if [ "${EMQX_LICENSE_CONF:-}" != "" ]; then + EMQX_LICENSE_CONF_OPTION="-c ${EMQX_LICENSE_CONF}" + fi + + ## timestamp for each generation + local NOW_TIME + NOW_TIME="$(call_hocon now_time)" + + ## ths command populates two files: app.