This commit is contained in:
Feng 2016-07-21 09:31:14 +08:00
parent 3e77773d04
commit 710890dd22
14 changed files with 738 additions and 506 deletions

3
.gitignore vendored
View File

@ -7,8 +7,6 @@ deps
erl_crash.dump
ebin
!ebin/.placeholder
rel/emqttd
rel/emqttd*
.concrete/DEV_MODE
.rebar
test/ebin/*.beam
@ -28,3 +26,4 @@ logs
ct.coverdata
.idea/
emqttd.iml
_rel/

View File

@ -2,46 +2,21 @@
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
POSIX_SHELL="true"
export POSIX_SHELL
# To support 'whoami' add /usr/ucb to path
PATH=/usr/ucb:$PATH
export PATH
exec /usr/bin/ksh $0 "$@"
fi
unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well
set -e
RUNNER_SCRIPT_DIR={{runner_script_dir}}
RUNNER_SCRIPT=${0##*/}
RUNNER_BASE_DIR={{runner_base_dir}}
RUNNER_ETC_DIR={{runner_etc_dir}}
RUNNER_LIB_DIR={{platform_lib_dir}}
RUNNER_LOG_DIR={{runner_log_dir}}
RUNNER_DATA_DIR=$RUNNER_BASE_DIR/data
RUNNER_PLUGINS_DIR=$RUNNER_BASE_DIR/plugins
# Note the trailing slash on $PIPE_DIR/
PIPE_DIR={{pipe_dir}}
RUNNER_USER={{runner_user}}
PLATFORM_DATA_DIR={{platform_data_dir}}
SSL_DIST_CONFIG=$PLATFORM_DATA_DIR/ssl_distribution.args_file
RIAK_VERSION="git"
WHOAMI=$(whoami)
# Make sure this script is running as the appropriate user
if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
type sudo > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
exit 1
fi
echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2
exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
fi
SCRIPT=$(readlink $0 || true)
if [ -z $SCRIPT ]; then
SCRIPT=$0
fi;
SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)"
RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd -P)"
REL_NAME="emqttd"
REL_VSN="{{ rel_vsn }}"
ERTS_VSN="{{ erts_vsn }}"
CODE_LOADING_MODE="${CODE_LOADING_MODE:-embedded}"
REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
ERL_OPTS="{{ erl_opts }}"
RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}"
# Warn the user if ulimit -n is less than 1024
ULIMIT_F=`ulimit -n`
@ -51,153 +26,231 @@ if [ "$ULIMIT_F" -lt 1024 ]; then
echo "!!!!"
fi
# Make sure CWD is set to runner base dir
cd $RUNNER_BASE_DIR
find_erts_dir() {
__erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
if [ -d "$__erts_dir" ]; then
ERTS_DIR="$__erts_dir";
ROOTDIR="$RELEASE_ROOT_DIR"
else
__erl="$(which erl)"
code="io:format(\"~s\", [code:root_dir()]), halt()."
__erl_root="$("$__erl" -noshell -eval "$code")"
ERTS_DIR="$__erl_root/erts-$ERTS_VSN"
ROOTDIR="$__erl_root"
fi
}
# Get node pid
relx_get_pid() {
if output="$(relx_nodetool rpcterms os getpid)"
then
echo "$output" | sed -e 's/"//g'
return 0
else
echo "$output"
return 1
fi
}
relx_get_nodename() {
id="longname$(relx_gen_id)-${NAME}"
"$BINDIR/erl" -boot start_clean -eval '[Host] = tl(string:tokens(atom_to_list(node()),"@")), io:format("~s~n", [Host]), halt()' -noshell ${NAME_TYPE} $id
}
# 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)"
# Setup remote shell command to control node
exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-setcookie "$COOKIE" -hidden -kernel net_ticktime $TICKTIME
}
# 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
"$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \
-setcookie "$COOKIE" "$command" $@
}
# Run an escript in the node's environment
relx_escript() {
shift; scriptpath="$1"; shift
export RELEASE_ROOT_DIR
"$ERTS_DIR/bin/escript" "$ROOTDIR/$scriptpath" $@
}
# Output a start command for the last argument of run_erl
relx_start_command() {
printf "exec \"%s\" \"%s\"" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \
"$START_OPTION"
}
# Use $CWD/vm.args if exists, otherwise releases/VSN/vm.args
if [ -z "$VMARGS_PATH" ]; then
if [ -f "$RELEASE_ROOT_DIR/vm.args" ]; then
VMARGS_PATH="$RELEASE_ROOT_DIR/vm.args"
else
VMARGS_PATH="$REL_DIR/vm.args"
fi
fi
orig_vmargs_path="$VMARGS_PATH.orig"
if [ $RELX_REPLACE_OS_VARS ]; then
#Make sure we don't break dev mode by keeping the symbolic link to
#the user's vm.args
if [ ! -L "$orig_vmargs_path" ]; then
#we're in copy mode, rename the vm.args file to vm.args.orig
mv "$VMARGS_PATH" "$orig_vmargs_path"
fi
awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < "$orig_vmargs_path" > "$VMARGS_PATH"
else
#We don't need to replace env. vars, just rename the
#symlink vm.args.orig to vm.args, and keep it as a
#symlink.
if [ -L "$orig_vmargs_path" ]; then
mv "$orig_vmargs_path" "$VMARGS_PATH"
fi
fi
# Make sure log directory exists
mkdir -p $RUNNER_LOG_DIR
mkdir -p "$RUNNER_LOG_DIR"
# Make sure the data directory exists
mkdir -p $PLATFORM_DATA_DIR
# Use $CWD/sys.config if exists, otherwise releases/VSN/sys.config
if [ -z "$RELX_CONFIG_PATH" ]; then
if [ -f "$RELEASE_ROOT_DIR/sys.config" ]; then
RELX_CONFIG_PATH="$RELEASE_ROOT_DIR/sys.config"
else
RELX_CONFIG_PATH="$REL_DIR/sys.config"
fi
fi
# Warn the user if they don't have write permissions on the log dir
if [ ! -w $RUNNER_LOG_DIR ]; then
echo "!!!!"
echo "!!!! WARNING: $RUNNER_LOG_DIR not writable; logs and crash dumps unavailable."
echo "!!!!"
orig_relx_config_path="$RELX_CONFIG_PATH.orig"
if [ $RELX_REPLACE_OS_VARS ]; then
#Make sure we don't break dev mode by keeping the symbolic link to
#the user's sys.config
if [ ! -L "$orig_relx_config_path" ]; then
#We're in copy mode, rename sys.config to sys.config.orig
mv "$RELX_CONFIG_PATH" "$orig_relx_config_path"
fi
awk '{while(match($0,"[$]{[^}]*}")) {var=substr($0,RSTART+2,RLENGTH -3);gsub("[$]{"var"}",ENVIRON[var])}}1' < "$orig_relx_config_path" > "$RELX_CONFIG_PATH"
else
#We don't need to replace env. vars, just rename the
#symlink sys.config.orig to sys.config. Keep it as
#a symlink.
if [ -L "$orig_relx_config_path" ]; then
mv "$orig_relx_config_path" "$RELX_CONFIG_PATH"
fi
fi
# Extract the target node name from node.args
NAME_ARG=`egrep '^\-s?name' $RUNNER_ETC_DIR/vm.args`
NAME_ARG=$(egrep '^-s?name' "$VMARGS_PATH" || true)
if [ -z "$NAME_ARG" ]; then
echo "vm.args needs to have either -name or -sname parameter."
exit 1
fi
NODE_NAME=${NAME_ARG##* }
# Extract the name type and name from the NAME_ARG for REMSH
NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')"
NAME="$(echo "$NAME_ARG" | awk '{print $2}')"
PIPE_DIR="${PIPE_DIR:-/tmp/erl_pipes/$NAME/}"
# Extract the target cookie
COOKIE_ARG=`grep '^\-setcookie' $RUNNER_ETC_DIR/vm.args`
COOKIE_ARG="$(grep '^-setcookie' "$VMARGS_PATH" || true)"
if [ -z "$COOKIE_ARG" ]; then
echo "vm.args needs to have a -setcookie parameter."
exit 1
fi
# Identify the script name
SCRIPT=`basename $0`
# Extract cookie name from COOKIE_ARG
COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')"
# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
find_erts_dir
export ROOTDIR="$RELEASE_ROOT_DIR"
export BINDIR="$ERTS_DIR/bin"
export EMU="beam"
export PROGNAME="erl"
export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH"
ERTS_LIB_DIR="$ERTS_DIR/../lib"
MNESIA_DATA_DIR="$ROOTDIR/data/mnesia/$NAME"
# Add ERTS bin dir to our path
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
cd "$ROOTDIR"
# Setup command to control the node
NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
NODETOOL_LITE="$ERTS_PATH/escript $ERTS_PATH/nodetool"
# Common functions
# Ping node without allowing nodetool to take stdin
ping_node() {
$NODETOOL ping < /dev/null
}
# Set the PID global variable, return 1 on error
get_pid() {
PID=`$NODETOOL getpid < /dev/null`
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
return 1
fi
# don't allow empty or init pid's
if [ -z $PID ] || [ "$PID" -le 1 ]; then
return 1
fi
return 0
}
# Scrape out SSL distribution config info from vm.args into $SSL_DIST_CONFIG
rm -f $SSL_DIST_CONFIG
sed -n '/Begin SSL distribution items/,/End SSL distribution items/p' \
$RUNNER_ETC_DIR/vm.args > $SSL_DIST_CONFIG
# User can specify an sname without @hostname
# This will fail when creating remote shell
# So here we check for @ and add @hostname if missing
case $NAME in
*@*)
# Nothing to do
;;
*)
NAME=$NAME@$(relx_get_nodename)
;;
esac
# Check the first argument for instructions
case "$1" in
start)
# Make sure there is not already a node running
RES=`ping_node`
if [ "$RES" = "pong" ]; then
echo "Node is already running!"
exit 1
fi
# Sanity check the emqttd.config file
RES=`$NODETOOL_LITE chkconfig $RUNNER_ETC_DIR/emqttd.config`
if [ $? != 0 ]; then
echo "Error reading $RUNNER_ETC_DIR/emqttd.config"
echo $RES
exit 1
fi
HEART_COMMAND="$RUNNER_SCRIPT_DIR/$SCRIPT start"
export HEART_COMMAND
mkdir -p $PIPE_DIR
$ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR \
"exec $RUNNER_SCRIPT_DIR/$SCRIPT console" 2>&1
start|start_boot)
# Wait for the node to come up. We can't just ping it because
# distributed erlang comes up for a second before emqttd crashes
# (eg. in the case of an unwriteable disk). Once the node comes
# up we check for the node watcher process. If that's running
# then we assume things are good enough. This will at least let
# the user know when emqttd is crashing right after startup.
WAIT=${WAIT_FOR_ERLANG:-15}
while [ $WAIT -gt 0 ]; do
WAIT=`expr $WAIT - 1`
sleep 1
RES=`ping_node`
if [ "$?" -ne 0 ]; then
continue
fi
echo "emqttd is started successfully!"
exit 0
done
echo "emqttd failed to start within ${WAIT_FOR_ERLANG:-15} seconds,"
echo "see the output of 'emqttd 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
# Make sure there is not already a node running
#RES=`$NODETOOL ping`
#if [ "$RES" = "pong" ]; then
# echo "Node is already running!"
# exit 1
#fi
# Save this for later.
CMD=$1
case "$1" in
start)
shift
START_OPTION="console"
HEART_OPTION="start"
;;
start_boot)
shift
START_OPTION="console_boot"
HEART_OPTION="start_boot"
;;
esac
RUN_PARAM="$@"
# Set arguments for the heart command
set -- "$SCRIPT_DIR/$REL_NAME" "$HEART_OPTION"
[ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM"
# Export the HEART_COMMAND
HEART_COMMAND="$RELEASE_ROOT_DIR/bin/$REL_NAME $CMD"
export HEART_COMMAND
mkdir -p "$PIPE_DIR"
"$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \
"$(relx_start_command)"
;;
stop)
UNAME_S=`uname -s`
case $UNAME_S in
Darwin)
# Make sure we explicitly set this because iTerm.app doesn't for
# some reason.
COMMAND_MODE=unix2003
esac
# Get the PID from nodetool
get_pid
GPR=$?
if [ "$GPR" -ne 0 ] || [ -z $PID ]; then
exit $GPR
fi
# Tell nodetool to initiate a stop
$NODETOOL stop
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
fi
# Wait for the node to completely stop...
while `kill -s 0 $PID 2>/dev/null`;
PID="$(relx_get_pid)"
if ! relx_nodetool "stop"; then
exit 1
fi
while $(kill -s 0 "$PID" 2>/dev/null);
do
sleep 1
done
@ -205,117 +258,214 @@ case "$1" in
restart)
## Restart the VM without exiting the process
$NODETOOL restart
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
if ! relx_nodetool "restart"; then
exit 1
fi
;;
reboot)
## Restart the VM completely (uses heart to restart it)
$NODETOOL reboot
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
if ! relx_nodetool "reboot"; then
exit 1
fi
;;
pid)
## Get the VM's pid
if ! relx_get_pid; then
exit 1
fi
;;
ping)
## See if the VM is alive
ping_node
ES=$?
if [ "$ES" -ne 0 ]; then
exit $ES
if ! relx_nodetool "ping"; then
exit 1
fi
;;
escript)
## Run an escript under the node's environment
if ! relx_escript $@; then
exit 1
fi
;;
attach)
if [ "$2" = "-f" ]; then
echo "Forcing connection..."
else
# Make sure a node is running
RES=`ping_node`
ES=$?
if [ "$ES" -ne 0 ]; then
echo "Node is not running!"
exit $ES
fi
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
shift
exec $ERTS_PATH/to_erl $PIPE_DIR
exec "$BINDIR/to_erl" "$PIPE_DIR"
;;
console)
RES=`ping_node`
if [ "$RES" = "pong" ]; then
echo "Node is already running - use '$SCRIPT attach' instead"
remote_console)
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
# Sanity check the emqttd.config file
RES=`$NODETOOL_LITE chkconfig $RUNNER_ETC_DIR/emqttd.config`
if [ $? != 0 ]; then
echo "Error reading $RUNNER_ETC_DIR/emqttd.config"
echo $RES
shift
relx_rem_sh
;;
upgrade|downgrade|install)
if [ -z "$2" ]; then
echo "Missing package argument"
echo "Usage: $REL_NAME $1 {package base name}"
echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
exit 1
fi
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
"install" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2"
;;
unpack)
if [ -z "$2" ]; then
echo "Missing package argument"
echo "Usage: $REL_NAME $1 {package base name}"
echo "NOTE {package base name} MUST NOT include the .tar.gz suffix"
exit 1
fi
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \
"unpack" "$REL_NAME" "$NAME_TYPE" "$NAME" "$COOKIE" "$2"
;;
console|console_clean|console_boot)
# .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 "$1" in
console)
if [ -f "$REL_DIR/$REL_NAME.boot" ]; then
BOOTFILE="$REL_DIR/$REL_NAME"
else
BOOTFILE="$REL_DIR/start"
fi
;;
console_clean)
BOOTFILE="$ROOTDIR/bin/start_clean"
;;
console_boot)
shift
BOOTFILE="$1"
shift
;;
esac
# Setup beam-required vars
ROOTDIR=$RUNNER_BASE_DIR
ERL_LIBS=$ROOTDIR/plugins
BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\///'`
# Setup Mnesia Dir
MNESIA_DIR="$RUNNER_DATA_DIR/mnesia/$NODE_NAME"
CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$SCRIPT \
-embedded -config $RUNNER_ETC_DIR/emqttd.config \
-pa $RUNNER_LIB_DIR/basho-patches \
-mnesia dir "\"${MNESIA_DIR}\"" \
-args_file $RUNNER_ETC_DIR/vm.args -- ${1+"$@"}"
EMU="beam"
PROGNAME="${0#*/}"
export EMU
export ROOTDIR
export ERL_LIBS
export BINDIR
export PROGNAME
# Store passed arguments since they will be erased by `set`
ARGS="$@"
# 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" \
-config "$RELX_CONFIG_PATH" \
-mnesia dir "\"${MNESIA_DATA_DIR}\"" \
-args_file "$VMARGS_PATH"
# Dump environment info for logging purposes
echo "Exec: $CMD"
echo "Exec: $@" -- ${1+$ARGS}
echo "Root: $ROOTDIR"
# Log the startup
logger -t "$SCRIPT[$$]" "Starting up"
echo "$RELEASE_ROOT_DIR"
logger -t "$REL_NAME[$$]" "Starting up"
# Start the VM
exec $CMD
exec "$@" -- ${1+$ARGS}
;;
chkconfig)
RES=`$NODETOOL_LITE chkconfig $RUNNER_ETC_DIR/emqttd.config`
if [ $? != 0 ]; then
echo "Error reading $RUNNER_ETC_DIR/emqttd.config"
echo $RES
foreground)
# start up the release in the foreground for use by runit
# or other supervision services
[ -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="$@"
# 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" -config "$RELX_CONFIG_PATH" \
-boot_var ERTS_LIB_DIR "$ERTS_LIB_DIR" \
-mnesia dir "\"${MNESIA_DATA_DIR}\"" \
-args_file "$VMARGS_PATH"
# Dump environment info for logging purposes
echo "Exec: $@" -- ${1+$ARGS}
echo "Root: $ROOTDIR"
# Start the VM
exec "$@" -- ${1+$ARGS}
;;
rpc)
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
echo "config is OK"
;;
escript)
shift
$ERTS_PATH/escript "$@"
relx_nodetool rpc $@
;;
version)
echo $RIAK_VERSION
;;
getpid)
# Get the PID from nodetool
get_pid
ES=$?
if [ "$ES" -ne 0 ] || [ -z $PID ]; then
exit $ES
rpcterms)
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
echo $PID
shift
relx_nodetool rpcterms $@
;;
eval)
# Make sure a node IS running
if ! relx_nodetool "ping" > /dev/null; then
echo "Node is not running!"
exit 1
fi
shift
relx_nodetool "eval" $@
;;
*)
echo "Usage: $SCRIPT {start|stop|restart|reboot|ping|console|attach|chkconfig|escript|version|getpid}"
echo "Usage: $REL_NAME {start|start_boot <file>|foreground|stop|restart|reboot|pid|ping|console|console_clean|console_boot <file>|attach|remote_console|upgrade|escript|rpc|rpcterms|eval}"
exit 1
;;
esac

View File

@ -2,90 +2,82 @@
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
POSIX_SHELL="true"
export POSIX_SHELL
# To support 'whoami' add /usr/ucb to path
PATH=/usr/ucb:$PATH
export PATH
exec /usr/bin/ksh $0 "$@"
fi
unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well
set -e
RUNNER_SCRIPT_DIR={{runner_script_dir}}
RUNNER_SCRIPT=${0##*/}
SCRIPT=$(readlink $0 || true)
if [ -z $SCRIPT ]; then
SCRIPT=$0
fi;
SCRIPT_DIR="$(cd `dirname "$SCRIPT"` && pwd -P)"
RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd -P)"
REL_NAME="emqttd"
REL_VSN="{{ rel_vsn }}"
ERTS_VSN="{{ erts_vsn }}"
REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN"
ERL_OPTS="{{ erl_opts }}"
RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}"
RUNNER_BASE_DIR={{runner_base_dir}}
RUNNER_ETC_DIR={{runner_etc_dir}}
RUNNER_LIB_DIR={{platform_lib_dir}}
RUNNER_LOG_DIR={{runner_log_dir}}
RUNNER_USER={{runner_user}}
WHOAMI=$(whoami)
# Make sure this script is running as the appropriate user
if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
type sudo > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
exit 1
find_erts_dir() {
__erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN"
if [ -d "$__erts_dir" ]; then
ERTS_DIR="$__erts_dir";
ROOTDIR="$RELEASE_ROOT_DIR"
else
__erl="$(which erl)"
code="io:format(\"~s\", [code:root_dir()]), halt()."
__erl_root="$("$__erl" -noshell -eval "$code")"
ERTS_DIR="$__erl_root/erts-$ERTS_VSN"
ROOTDIR="$__erl_root"
fi
echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2
exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
fi
}
# Make sure CWD is set to runner base dir
cd $RUNNER_BASE_DIR
relx_get_nodename() {
id="longname$(relx_gen_id)-${NAME}"
"$BINDIR/erl" -boot start_clean -eval '[Host] = tl(string:tokens(atom_to_list(node()),"@")), io:format("~s~n", [Host]), halt()' -noshell ${NAME_TYPE} $id
}
# Control a node
relx_nodetool() {
command="$1"; shift
"$ERTS_DIR/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \
-setcookie "$COOKIE" "$command" $@
}
# Use $CWD/vm.args if exists, otherwise releases/VSN/vm.args
if [ -z "$VMARGS_PATH" ]; then
if [ -f "$RELEASE_ROOT_DIR/vm.args" ]; then
VMARGS_PATH="$RELEASE_ROOT_DIR/vm.args"
else
VMARGS_PATH="$REL_DIR/vm.args"
fi
fi
# Extract the target node name from node.args
NAME_ARG=`egrep "^ *-s?name" $RUNNER_ETC_DIR/vm.args`
NAME_ARG=$(egrep '^-s?name' "$VMARGS_PATH" || true)
if [ -z "$NAME_ARG" ]; then
echo "vm.args needs to have either -name or -sname parameter."
exit 1
fi
# Learn how to specify node name for connection from remote nodes
echo "$NAME_ARG" | grep '^-sname' > /dev/null 2>&1
if [ "X$?" = "X0" ]; then
NAME_PARAM="-sname"
NAME_HOST=""
else
NAME_PARAM="-name"
echo "$NAME_ARG" | grep '@.*' > /dev/null 2>&1
if [ "X$?" = "X0" ]; then
NAME_HOST=`echo "${NAME_ARG}" | sed -e 's/.*\(@.*\)$/\1/'`
else
NAME_HOST=""
fi
fi
# Extract the name type and name from the NAME_ARG for REMSH
NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')"
NAME="$(echo "$NAME_ARG" | awk '{print $2}')"
# Extract the target cookie
COOKIE_ARG=`grep '\-setcookie' $RUNNER_ETC_DIR/vm.args`
COOKIE_ARG="$(grep '^-setcookie' "$VMARGS_PATH" || true)"
if [ -z "$COOKIE_ARG" ]; then
echo "vm.args needs to have a -setcookie parameter."
exit 1
fi
# Identify the script name
SCRIPT=`basename $0`
# Extract cookie name from COOKIE_ARG
COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')"
# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
find_erts_dir
export ROOTDIR="$RELEASE_ROOT_DIR"
export BINDIR="$ERTS_DIR/bin"
cd "$ROOTDIR"
# Add ERTS bin dir to our path
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
# Setup command to control the node
NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
RES=`$NODETOOL ping`
if [ "$RES" != "pong" ]; then
echo "Node is not running!"
exit 1
fi
$NODETOOL rpc emqttd_ctl run $@
relx_nodetool rpc emqttd_ctl run $@

View File

@ -1,117 +0,0 @@
#!/bin/sh
# -*- tab-width:4;indent-tabs-mode:nil -*-
# ex: ts=4 sw=4 et
# /bin/sh on Solaris is not a POSIX compatible shell, but /usr/bin/ksh is.
if [ `uname -s` = 'SunOS' -a "${POSIX_SHELL}" != "true" ]; then
POSIX_SHELL="true"
export POSIX_SHELL
# To support 'whoami' add /usr/ucb to path
PATH=/usr/ucb:$PATH
export PATH
exec /usr/bin/ksh $0 "$@"
fi
unset POSIX_SHELL # clear it so if we invoke other scripts, they run as ksh as well
RUNNER_SCRIPT_DIR={{runner_script_dir}}
RUNNER_SCRIPT=${0##*/}
RUNNER_BASE_DIR={{runner_base_dir}}
RUNNER_ETC_DIR={{runner_etc_dir}}
RUNNER_LIB_DIR={{platform_lib_dir}}
RUNNER_USER={{runner_user}}
WHOAMI=$(whoami)
# Make sure this script is running as the appropriate user
if ([ "$RUNNER_USER" ] && [ "x$WHOAMI" != "x$RUNNER_USER" ]); then
type sudo > /dev/null 2>&1
if [ $? -ne 0 ]; then
echo "sudo doesn't appear to be installed and your EUID isn't $RUNNER_USER" 1>&2
exit 1
fi
echo "Attempting to restart script through sudo -H -u $RUNNER_USER" >&2
exec sudo -H -u $RUNNER_USER -i $RUNNER_SCRIPT_DIR/$RUNNER_SCRIPT $@
fi
# Make sure CWD is set to runner base dir
cd $RUNNER_BASE_DIR
# Extract the target node name from node.args
NAME_ARG=`egrep "^ *-s?name" $RUNNER_ETC_DIR/vm.args`
if [ -z "$NAME_ARG" ]; then
echo "vm.args needs to have either -name or -sname parameter."
exit 1
fi
# Learn how to specify node name for connection from remote nodes
echo "$NAME_ARG" | grep '^-sname' > /dev/null 2>&1
if [ "X$?" = "X0" ]; then
NAME_PARAM="-sname"
NAME_HOST=""
else
NAME_PARAM="-name"
echo "$NAME_ARG" | grep '@.*' > /dev/null 2>&1
if [ "X$?" = "X0" ]; then
NAME_HOST=`echo "${NAME_ARG}" | sed -e 's/.*\(@.*\)$/\1/'`
else
NAME_HOST=""
fi
fi
# Extract the target cookie
COOKIE_ARG=`grep '\-setcookie' $RUNNER_ETC_DIR/vm.args`
if [ -z "$COOKIE_ARG" ]; then
echo "vm.args needs to have a -setcookie parameter."
exit 1
fi
# Identify the script name
SCRIPT=`basename $0`
# Parse out release and erts info
START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data`
ERTS_VSN=${START_ERL% *}
APP_VSN=${START_ERL#* }
# Add ERTS bin dir to our path
ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin
NODE_NAME=${NAME_ARG#* }
# Setup command to control the node
NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG"
RES=`$NODETOOL ping`
if [ "$RES" != "pong" ]; then
echo "Node is not running!"
exit 1
fi
case "$1" in
runtime)
SORTBY="runtime"
;;
reductions)
SORTBY="reductions"
;;
memory)
SORTBY="memory"
;;
msg_q)
SORTBY="msg_q"
;;
*)
echo "Usage: $SCRIPT {runtime | reductions | memory | msg_q}"
exit 1
;;
esac
MYPID=$$
ETOP_ARGS="-sort $SORTBY -interval 10 -lines 50 -tracing off"
$ERTS_PATH/erl -noshell -noinput \
-pa $RUNNER_LIB_DIR/basho-patches \
-hidden $NAME_PARAM emqttd_top$MYPID$NAME_HOST $COOKIE_ARG \
-s etop -s erlang halt -output text \
-node $NODE_NAME $ETOP_ARGS

View File

@ -1,44 +0,0 @@
#!/usr/bin/env escript
%%! -noshell -noinput
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
-define(TIMEOUT, 60000).
-define(INFO(Fmt,Args), io:format(Fmt,Args)).
main([NodeName, Cookie, ReleasePackage]) ->
TargetNode = start_distribution(NodeName, Cookie),
{ok, Vsn} = rpc:call(TargetNode, release_handler, unpack_release,
[ReleasePackage], ?TIMEOUT),
?INFO("Unpacked Release ~p~n", [Vsn]),
{ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
check_install_release, [Vsn], ?TIMEOUT),
{ok, OtherVsn, Desc} = rpc:call(TargetNode, release_handler,
install_release, [Vsn], ?TIMEOUT),
?INFO("Installed Release ~p~n", [Vsn]),
ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT),
?INFO("Made Release ~p Permanent~n", [Vsn]);
main(_) ->
init:stop(1).
start_distribution(NodeName, Cookie) ->
MyNode = make_script_node(NodeName),
{ok, _Pid} = net_kernel:start([MyNode, shortnames]),
erlang:set_cookie(node(), list_to_atom(Cookie)),
TargetNode = make_target_node(NodeName),
case {net_kernel:hidden_connect_node(TargetNode),
net_adm:ping(TargetNode)} of
{true, pong} ->
ok;
{_, pang} ->
io:format("Node ~p not responding to pings.\n", [TargetNode]),
init:stop(1)
end,
TargetNode.
make_target_node(Node) ->
[_, Host] = string:tokens(atom_to_list(node()), "@"),
list_to_atom(lists:concat([Node, "@", Host])).
make_script_node(Node) ->
list_to_atom(lists:concat([Node, "_upgrader_", os:getpid()])).

143
bin/install_upgrade_escript Executable file
View File

@ -0,0 +1,143 @@
#!/usr/bin/env escript
%%! -noshell -noinput
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
-define(TIMEOUT, 300000).
-define(INFO(Fmt,Args), io:format(Fmt,Args)).
%% Unpack or upgrade to a new tar.gz release
main(["unpack", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) ->
TargetNode = start_distribution(NodeName, NameTypeArg, Cookie),
WhichReleases = which_releases(TargetNode),
Version = parse_version(VersionArg),
case proplists:get_value(Version, WhichReleases) of
undefined ->
%% not installed, so unpack tarball:
?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]),
ReleasePackage = Version ++ "/" ++ RelName,
case rpc:call(TargetNode, release_handler, unpack_release,
[ReleasePackage], ?TIMEOUT) of
{ok, Vsn} ->
?INFO("Unpacked successfully: ~p~n", [Vsn]);
{error, UnpackReason} ->
print_existing_versions(TargetNode),
?INFO("Unpack failed: ~p~n",[UnpackReason]),
erlang:halt(2)
end;
old ->
%% no need to unpack, has been installed previously
?INFO("Release ~s is marked old, switching to it.~n",[Version]);
unpacked ->
?INFO("Release ~s is already unpacked, now installing.~n",[Version]);
current ->
?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]);
permanent ->
?INFO("Release ~s is already installed, and set permanent.~n",[Version])
end;
main(["install", RelName, NameTypeArg, NodeName, Cookie, VersionArg]) ->
TargetNode = start_distribution(NodeName, NameTypeArg, Cookie),
WhichReleases = which_releases(TargetNode),
Version = parse_version(VersionArg),
case proplists:get_value(Version, WhichReleases) of
undefined ->
%% not installed, so unpack tarball:
?INFO("Release ~s not found, attempting to unpack releases/~s/~s.tar.gz~n",[Version,Version,RelName]),
ReleasePackage = Version ++ "/" ++ RelName,
case rpc:call(TargetNode, release_handler, unpack_release,
[ReleasePackage], ?TIMEOUT) of
{ok, Vsn} ->
?INFO("Unpacked successfully: ~p~n", [Vsn]),
install_and_permafy(TargetNode, RelName, Vsn);
{error, UnpackReason} ->
print_existing_versions(TargetNode),
?INFO("Unpack failed: ~p~n",[UnpackReason]),
erlang:halt(2)
end;
old ->
%% no need to unpack, has been installed previously
?INFO("Release ~s is marked old, switching to it.~n",[Version]),
install_and_permafy(TargetNode, RelName, Version);
unpacked ->
?INFO("Release ~s is already unpacked, now installing.~n",[Version]),
install_and_permafy(TargetNode, RelName, Version);
current -> %% installed and in-use, just needs to be permanent
?INFO("Release ~s is already installed and current. Making permanent.~n",[Version]),
permafy(TargetNode, RelName, Version);
permanent ->
?INFO("Release ~s is already installed, and set permanent.~n",[Version])
end;
main(_) ->
erlang:halt(1).
parse_version(V) when is_list(V) ->
hd(string:tokens(V,"/")).
install_and_permafy(TargetNode, RelName, Vsn) ->
case rpc:call(TargetNode, release_handler, check_install_release, [Vsn], ?TIMEOUT) of
{ok, _OtherVsn, _Desc} ->
ok;
{error, Reason} ->
?INFO("ERROR: release_handler:check_install_release failed: ~p~n",[Reason]),
erlang:halt(3)
end,
case rpc:call(TargetNode, release_handler, install_release, [Vsn], ?TIMEOUT) of
{ok, _, _} ->
?INFO("Installed Release: ~s~n", [Vsn]),
permafy(TargetNode, RelName, Vsn),
ok;
{error, {no_such_release, Vsn}} ->
VerList =
iolist_to_binary(
[io_lib:format("* ~s\t~s~n",[V,S]) || {V,S} <- which_releases(TargetNode)]),
?INFO("Installed versions:~n~s", [VerList]),
?INFO("ERROR: Unable to revert to '~s' - not installed.~n", [Vsn]),
erlang:halt(2)
end.
permafy(TargetNode, RelName, Vsn) ->
ok = rpc:call(TargetNode, release_handler, make_permanent, [Vsn], ?TIMEOUT),
file:copy(filename:join(["bin", RelName++"-"++Vsn]),
filename:join(["bin", RelName])),
?INFO("Made release permanent: ~p~n", [Vsn]),
ok.
which_releases(TargetNode) ->
R = rpc:call(TargetNode, release_handler, which_releases, [], ?TIMEOUT),
[ {V, S} || {_,V,_, S} <- R ].
print_existing_versions(TargetNode) ->
VerList = iolist_to_binary([
io_lib:format("* ~s\t~s~n",[V,S])
|| {V,S} <- which_releases(TargetNode) ]),
?INFO("Installed versions:~n~s", [VerList]).
start_distribution(NodeName, NameTypeArg, Cookie) ->
MyNode = make_script_node(NodeName),
{ok, _Pid} = net_kernel:start([MyNode, get_name_type(NameTypeArg)]),
erlang:set_cookie(node(), list_to_atom(Cookie)),
TargetNode = list_to_atom(NodeName),
case {net_kernel:connect_node(TargetNode),
net_adm:ping(TargetNode)} of
{true, pong} ->
ok;
{_, pang} ->
io:format("Node ~p not responding to pings.\n", [TargetNode]),
erlang:halt(1)
end,
{ok, Cwd} = file:get_cwd(),
ok = rpc:call(TargetNode, file, set_cwd, [Cwd], ?TIMEOUT),
TargetNode.
make_script_node(Node) ->
[Name, Host] = string:tokens(Node, "@"),
list_to_atom(lists:concat([Name, "_upgrader_", os:getpid(), "@", Host])).
%% get name type from arg
get_name_type(NameTypeArg) ->
case NameTypeArg of
"-sname" ->
shortnames;
_ ->
longnames
end.

View File

@ -1,5 +1,4 @@
#!/usr/bin/env escript
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
%% -------------------------------------------------------------------
@ -38,8 +37,8 @@ main(Args) ->
{error, {Line, Mod, Term}} ->
io:format(standard_error, ["Error on line ", file:format_error({Line, Mod, Term}), "\n"], []),
halt(1);
{error, R} ->
io:format(standard_error, ["Error reading config file: ", file:format_error(R), "\n"], []),
{error, Error} ->
io:format(standard_error, ["Error reading config file: ", file:format_error(Error), "\n"], []),
halt(1)
end;
_ ->
@ -94,20 +93,48 @@ main(Args) ->
end;
["rpcterms", Module, Function, ArgsAsString] ->
case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function),
consult(ArgsAsString), 60000) of
consult(lists:flatten(ArgsAsString)), 60000) of
{badrpc, Reason} ->
io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
halt(1);
Other ->
io:format("~p\n", [Other])
end;
["eval" | ListOfArgs] ->
% shells may process args into more than one, and end up stripping
% spaces, so this converts all of that to a single string to parse
String = binary_to_list(
list_to_binary(
string:join(ListOfArgs," ")
)
),
% then just as a convenience to users, if they forgot a trailing
% '.' add it for them.
Normalized =
case lists:reverse(String) of
[$. | _] -> String;
R -> lists:reverse([$. | R])
end,
% then scan and parse the string
{ok, Scanned, _} = erl_scan:string(Normalized),
{ok, Parsed } = erl_parse:parse_exprs(Scanned),
% and evaluate it on the remote node
case rpc:call(TargetNode, erl_eval, exprs, [Parsed, [] ]) of
{value, Value, _} ->
io:format ("~p\n",[Value]);
{badrpc, Reason} ->
io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]),
halt(1)
end;
Other ->
io:format("Other: ~p\n", [Other]),
io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms}\n")
io:format("Usage: nodetool {chkconfig|getpid|ping|stop|restart|reboot|rpc|rpc_infinity|rpcterms|eval [Terms]} [RPC]\n")
end,
net_kernel:stop().
process_args([], Acc, TargetNode) ->
{lists:reverse(Acc), TargetNode};
process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) ->
@ -126,7 +153,7 @@ process_args([Arg | Rest], Acc, Opts) ->
start_epmd() ->
[] = os:cmd(epmd_path() ++ " -daemon"),
[] = os:cmd("\"" ++ epmd_path() ++ "\" -daemon"),
ok.
epmd_path() ->
@ -163,7 +190,6 @@ append_node_suffix(Name, Suffix) ->
list_to_atom(lists:concat([Node, Suffix, os:getpid()]))
end.
%%
%% Given a string or binary, parse it into a list of terms, ala file:consult/0
%%
@ -188,7 +214,6 @@ consult(Cont, Str, Acc) ->
consult(Cont1, eof, Acc)
end.
%%
%% Validation functions for checking the emqttd.config
%%
@ -211,4 +236,3 @@ print_issue({warning, Warning}) ->
print_issue({error, Error}) ->
io:format(standard_error, "Error in emqttd.config: ~s~n", [Error]).

View File

@ -1,3 +1,27 @@
%%===================================================================
%%
%% Config file for emqttd 2.0
%%
%% Erlang Term Syntax:
%%
%% {}: Tuple, usually {Key, Value}
%% []: List, seperated by comma
%% %%: comment
%%
%%===================================================================
%%--------------------------------------------------------------------
%% MQTT Protocol
%%--------------------------------------------------------------------
%% Max ClientId Length Allowed.
{mqtt_max_clientid_len, 512}.
%% Max Packet Size Allowed, 64K by default.
{mqtt_max_packet_size, 65536}.
%% Client Idle Timeout.
{mqtt_client_idle_timeout, 30}. % Second
%%--------------------------------------------------------------------
%% Authentication
@ -11,7 +35,7 @@
{auth, username, [{passwd, "etc/passwd.conf"}, {passwd_hash, plain}]}.
%% Authentication with clientId
{auth, clientid, [{clients, "etc/client.config"}, {password, no}]}.
{auth, clientid, [{config, "etc/client.config"}, {password, no}]}.
%%--------------------------------------------------------------------
%% ACL
@ -42,25 +66,12 @@
{retained_max_playload_size, 65536}.
%%--------------------------------------------------------------------
%% MQTT Protocol
%%--------------------------------------------------------------------
%% Max ClientId Length Allowed.
{mqtt_max_clientid_len, 512}.
%% Max Packet Size Allowed, 64K by default.
{mqtt_max_packet_size, 65536}.
%% Socket Idle Timeout.
{mqtt_client_idle_timeout, 30}. % Seconds
%%--------------------------------------------------------------------
%% MQTT Session
%% Session
%%--------------------------------------------------------------------
%% Max number of QoS 1 and 2 messages that can be “inflight” at one time.
%% 0 means no limit
{session_max_inflight, 100}.
{session_max_inflight, 100}.
%% Retry interval for redelivering QoS1/2 messages.
{session_unack_retry_interval, 60}.
@ -101,7 +112,13 @@
{queue_qos0, true}.
%%--------------------------------------------------------------------
%% Listeners
%% Zone
%%--------------------------------------------------------------------
{zone, admin, []}.
%%--------------------------------------------------------------------
%% Listener
%%--------------------------------------------------------------------
%% Plain MQTT
@ -112,6 +129,9 @@
%% Maximum number of concurrent clients
{max_clients, 512},
%% Mount point prefix
%% {mount_point, "prefix/"},
%% Socket Access Control
{access, [{allow, all}]},
@ -132,7 +152,7 @@
]}
]}.
%% MQTT SSL
%% MQTT/SSL
{listener, mqtts, 8883, [
%% Size of acceptor pool
{acceptors, 4},
@ -179,8 +199,12 @@
%% PubSub and Router. Default should be scheduler numbers.
{pubsub_pool_size, 8}.
%%--------------------------------------------------------------------
%% Routing
%%--------------------------------------------------------------------
%% Route aging time(seconds)
{pubsub_routing_age, 5}.
{routing_age, 5}.
%%--------------------------------------------------------------------
%% Bridge
@ -196,35 +220,22 @@
%% Plugins
%%-------------------------------------------------------------------
%% Plugins Dir
{plugins_dir, "./plugins"}.
%% File to store loaded plugin names.
{plugins_loaded_file, "./data/loaded_plugins"}.
{plugins_loaded_file, "data/loaded_plugins"}.
%%-------------------------------------------------------------------
%%--------------------------------------------------------------------
%% Modules
%%-------------------------------------------------------------------
%%--------------------------------------------------------------------
%% Client presence management module. Publish presence messages when client connected or disconnected
%% Client presence management module. Publish presence messages when
%% client connected or disconnected.
{module, presence, [{qos, 0}]}.
%% Subscribe topics automatically when client connected
{module, subscription, [{"$queue/clients/$c", 1}, backend]}.
%% [Rewrite](https://github.com/emqtt/emqttd/wiki/Rewrite)
{module, rewrite, [
%{topic, "x/#", [
% {rewrite, "^x/y/(.+)$", "z/y/$1"},
% {rewrite, "^x/(.+)$", "y/$1"}
%]},
%{topic, "y/+/z/#", [
% {rewrite, "^y/(.+)/z/(.+)$", "y/z/$2"}
%]}
]}.
{module, rewrite, [{config, "etc/rewrite.conf"}]}.
%%-------------------------------------------------------------------
%% Erlang System Monitor

14
etc/rewrite.conf Normal file
View File

@ -0,0 +1,14 @@
%%--------------------------------------------------------------------
%% [Rewrite](https://github.com/emqtt/emqttd/wiki/Rewrite)
%%--------------------------------------------------------------------
%{topic, "x/#", [
% {rewrite, "^x/y/(.+)$", "z/y/$1"},
% {rewrite, "^x/(.+)$", "y/$1"}
%]}.
%{topic, "y/+/z/#", [
% {rewrite, "^y/(.+)/z/(.+)$", "y/z/$2"}
%]}.

19
rel/vars.config Normal file
View File

@ -0,0 +1,19 @@
%% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*-
%% ex: ft=erlang ts=4 sw=4 et
%% Platform-specific installation paths
{platform_bin_dir, "./bin"}.
{platform_data_dir, "./data"}.
{platform_etc_dir, "./etc"}.
{platform_lib_dir, "./lib"}.
{platform_log_dir, "./log"}.
%%
%% bin/emqttd
%%
%% {runner_script_dir, "$(cd ${0%/*} && pwd)"}.
{runner_base_dir, "${RUNNER_SCRIPT_DIR%/*}"}.
{runner_etc_dir, "$RUNNER_BASE_DIR/etc"}.
{runner_log_dir, "$RUNNER_BASE_DIR/log"}.
{pipe_dir, "/tmp/$RUNNER_SCRIPT/"}.
{runner_user, ""}.

BIN
relx Executable file

Binary file not shown.

41
relx.config Normal file
View File

@ -0,0 +1,41 @@
{release, {emqttd, "2.0"}, [
sasl,
os_mon,
runtime_tools,
{mnesia, load},
emqttd
]}.
{include_src, false}.
{extended_start_script, false}.
{sys_config, "rel/sys.config"}.
{vm_args, "rel/vm.args"}.
{overlay_vars, "./rel/vars.config"}.
{overlay, [
{mkdir, "etc/"},
{mkdir, "etc/ssl/"},
{mkdir, "data/"},
{mkdir, "data/mnesia"},
{mkdir, "log/"},
{copy, "etc/ssl/ssl.crt", "etc/ssl/ssl.crt"},
{copy, "etc/ssl/ssl.key", "etc/ssl/ssl.key"},
{template, "bin/emqttd", "bin/emqttd"},
{template, "bin/emqttd_ctl", "bin/emqttd_ctl"},
{copy, "bin/nodetool", "bin/nodetool"},
{copy, "bin/nodetool", "erts-\{\{erts_vsn\}\}/bin/nodetool"},
{copy, "bin/install_upgrade_escript", "bin/install_upgrade_escript"},
{template, "etc/acl.conf", "etc/acl.conf"},
{template, "etc/client.conf", "etc/client.conf"},
{template, "etc/emqttd.conf", "etc/emqttd.conf"},
{template, "etc/passwd.conf", "etc/passwd.conf"},
{template, "etc/rewrite.conf", "etc/rewrite.conf"}
]}.

View File

@ -5,7 +5,7 @@
{id, "emqttd"},
{modules, []},
{registered, []},
{applications, [kernel, stdlib, gproc, esockd, mochiweb]},
{applications, [kernel, stdlib, gproc, esockd, mochiweb, gen_logger, gen_conf]},
{mod, {emqttd_app, []}},
{env, []}
]}.

View File

@ -39,7 +39,7 @@
%% Client State
-record(client_state, {connection, connname, peername, peerhost, peerport,
await_recv, conn_state, rate_limit, parser_fun,
proto_state, packet_opts, keepalive}).
proto_state, packet_opts, keepalive, mountpoint}).
-define(INFO_KEYS, [peername, peerhost, peerport, await_recv, conn_state]).