Refactor ejabberdctl

This commit is contained in:
Christophe Romain 2017-05-31 18:11:45 +02:00
parent 0042f18c1f
commit cbe6553baa
1 changed files with 147 additions and 259 deletions

View File

@ -10,159 +10,95 @@ FIREWALL_WINDOW=""
ERLANG_NODE=ejabberd@localhost ERLANG_NODE=ejabberd@localhost
# define default environment variables # define default environment variables
SCRIPT_DIR=`cd ${0%/*} && pwd`
ERL={{erl}} ERL={{erl}}
IEX={{bindir}}/iex IEX={{bindir}}/iex
EPMD={{epmd}} EPMD={{epmd}}
INSTALLUSER={{installuser}} INSTALLUSER={{installuser}}
ERL_LIBS={{libdir}}
# check the proper system user is used if defined # check the proper system user is used if defined
if [ "$INSTALLUSER" != "" ] ; then EXEC_CMD="false"
EXEC_CMD="false" if [ -n "$INSTALLUSER" ] ; then
for GID in `id -G`; do if [ $(id -g) -eq $(id -g $INSTALLUSER || echo -1) ] ; then
if [ $GID -eq 0 ] ; then
INSTALLUSER_HOME=$(getent passwd "$INSTALLUSER" | cut -d: -f6)
if [ -n "$INSTALLUSER_HOME" ] && [ ! -d "$INSTALLUSER_HOME" ] ; then
mkdir -p "$INSTALLUSER_HOME"
chown "$INSTALLUSER" "$INSTALLUSER_HOME"
fi
EXEC_CMD="as_install_user"
fi
done
if [ `id -g` -eq `id -g $INSTALLUSER` ] ; then
EXEC_CMD="as_current_user" EXEC_CMD="as_current_user"
fi else
if [ "$EXEC_CMD" = "false" ] ; then id -Gn | grep -q wheel && EXEC_CMD="as_install_user"
echo "This command can only be run by root or the user $INSTALLUSER" >&2
exit 4
fi fi
else else
EXEC_CMD="as_current_user" EXEC_CMD="as_current_user"
fi fi
if [ "$EXEC_CMD" = "false" ] ; then
echo "ERROR: This command can only be run by root or the user $INSTALLUSER" >&2
exit 7
fi
# run command either directly or via su $INSTALLUSER # set backward compatibility on command line parameters
exec_cmd() set -- $(echo "$*" | sed -e \
{ "s/--node/-n/;s/--spool/-s/;s/--logs/-l/;\
if [ "EXEC_CMD" = as_install_user ]; then s/--config/-f/;s/--ctl-config/-c/;s/--config-dir/-d/;\
su -c '"$0" $@"' "INSTALLUSER" -- "$@" s/--no-timeout/-t/")
else
"$@"
fi
}
# parse command line parameters # parse command line parameters
next=init while getopts n:s:l:f:c:d:tx opt; do
for arg; do case $opt in
# Empty argument list as it is already saved in the for buffer n) ERLANG_NODE_ARG=$OPTARG;;
if [ "$next" = init ]; then s) SPOOL_DIR=$OPTARG;;
next= l) LOGS_DIR=$OPTARG;;
set -- f) EJABBERD_CONFIG_PATH=$OPTARG;;
fi c) EJABBERDCTL_CONFIG_PATH=$OPTARG;;
case $next in d) ETC_DIR=$OPTARG;;
node) ERLANG_NODE_ARG=$arg; next=;; t) NO_TIMEOUT="--no-timeout";;
config-dir) ETC_DIR=$arg; next=;;
config) EJABBERD_CONFIG_PATH=$arg; next=;;
ctl-config) EJABBERDCTL_CONFIG_PATH=$arg; next=;;
logs) LOGS_DIR=$arg; next=;;
spool) SPOOL_DIR=$arg; next=;;
"")
case $arg in
--) next=raw;;
--no-timeout) EJABBERD_NO_TIMEOUT="--no-timeout" ;;
--node) next=node;;
--config-dir) next=config-dir;;
--config) next=config;;
--ctl-config) next=ctl-config;;
--logs) next=logs;;
--spool) next=spool;;
*) set -- "$@" "$arg";; # unknown option, keep it.
esac;;
raw) # we are after --, keep options as it is.
set -- "$@" "$arg";;
esac esac
done done
# keep extra command line parameters for ejabberd
shift $((OPTIND-1))
# Define ejabberd variable if they have not been defined from the command line # define ejabberd variables if not already defined from the command line
if [ "$ETC_DIR" = "" ] ; then : ${ETC_DIR:={{sysconfdir}}/ejabberd}
ETC_DIR={{sysconfdir}}/ejabberd : ${LOGS_DIR:={{localstatedir}}/log/ejabberd}
fi : ${SPOOL_DIR:={{localstatedir}}/lib/ejabberd}
if [ "$EJABBERDCTL_CONFIG_PATH" = "" ] ; then : ${EJABBERD_CONFIG_PATH:="$ETC_DIR"/ejabberd.yml}
EJABBERDCTL_CONFIG_PATH=$ETC_DIR/ejabberdctl.cfg : ${EJABBERDCTL_CONFIG_PATH:="$ETC_DIR"/ejabberdctl.cfg}
fi [ -f "$EJABBERDCTL_CONFIG_PATH" ] && . "$EJABBERDCTL_CONFIG_PATH"
if [ -f "$EJABBERDCTL_CONFIG_PATH" ] ; then [ "$ERLANG_NODE_ARG" != "" ] && ERLANG_NODE=$ERLANG_NODE_ARG
. "$EJABBERDCTL_CONFIG_PATH" : ${EJABBERD_DOC_PATH:={{docdir}}}
fi : ${EJABBERD_LOG_PATH:="$LOGS_DIR"/ejabberd.log}
if [ "$EJABBERD_CONFIG_PATH" = "" ] ; then
EJABBERD_CONFIG_PATH=$ETC_DIR/ejabberd.yml
fi
if [ "$LOGS_DIR" = "" ] ; then
LOGS_DIR={{localstatedir}}/log/ejabberd
fi
if [ "$SPOOL_DIR" = "" ] ; then
SPOOL_DIR={{localstatedir}}/lib/ejabberd
fi
if [ "$EJABBERD_DOC_PATH" = "" ] ; then
EJABBERD_DOC_PATH={{docdir}}
fi
if [ "$ERLANG_NODE_ARG" != "" ] ; then
ERLANG_NODE=$ERLANG_NODE_ARG
fi
if [ "{{release}}" != "true" -a "$EJABBERD_BIN_PATH" = "" ] ; then
EJABBERD_BIN_PATH={{libdir}}/ejabberd/priv/bin
fi
EJABBERD_LOG_PATH=$LOGS_DIR/ejabberd.log
DATETIME=`date "+%Y%m%d-%H%M%S"`
ERL_CRASH_DUMP=$LOGS_DIR/erl_crash_$DATETIME.dump
ERL_INETRC=$ETC_DIR/inetrc
# define mnesia options
MNESIA_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS"
# define erl parameters # define erl parameters
ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS" ERLANG_OPTS="+K $POLL -smp $SMP +P $ERL_PROCESSES $ERL_OPTIONS"
KERNEL_OPTS=""
if [ "$FIREWALL_WINDOW" != "" ] ; then if [ "$FIREWALL_WINDOW" != "" ] ; then
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_listen_min ${FIREWALL_WINDOW%-*} inet_dist_listen_max ${FIREWALL_WINDOW#*-}" ERLANG_OPTS="$ERLANG_OPTS -kernel " \
"inet_dist_listen_min ${FIREWALL_WINDOW%-*} " \
"inet_dist_listen_max ${FIREWALL_WINDOW#*-}"
fi fi
if [ "$INET_DIST_INTERFACE" != "" ] ; then if [ "$INET_DIST_INTERFACE" != "" ] ; then
INET_DIST_INTERFACE2="$(echo $INET_DIST_INTERFACE | sed 's/\./,/g')" INET_DIST_INTERFACE2=$("$ERL" -noshell -eval 'case inet:parse_address("'$INET_DIST_INTERFACE'") of {ok,IP} -> io:format("~p",[IP]); _ -> ok end.' -s erlang halt)
if [ "$INET_DIST_INTERFACE" != "$INET_DIST_INTERFACE2" ] ; then if [ "$INET_DIST_INTERFACE2" != "" ] ; then
INET_DIST_INTERFACE2="{$INET_DIST_INTERFACE2}" ERLANG_OPTS="$ERLANG_OPTS -kernel inet_dist_use_interface \"$INET_DIST_INTERFACE2\""
fi fi
KERNEL_OPTS="${KERNEL_OPTS} -kernel inet_dist_use_interface \"${INET_DIST_INTERFACE2}\""
fi fi
if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then if [ "$ERLANG_NODE" = "${ERLANG_NODE%.*}" ] ; then
NAME="-sname" NAME="-sname"
else else
NAME="-name" NAME="-name"
fi fi
IEXNAME="-$NAME" ERL_LIBS={{libdir}}
ERL_CRASH_DUMP="$LOGS_DIR"/erl_crash_$(date "+%Y%m%d-%H%M%S").dump
ERL_INETRC="$ETC_DIR"/inetrc
# define ejabberd environment parameters # define ejabberd parameters
if [ "$EJABBERD_CONFIG_PATH" != "${EJABBERD_CONFIG_PATH%.yml}" ] ; then rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH")
rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH")
rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) count=$(sed '/^[ ]*log_rotate_count/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH")
count=$(sed '/^[ ]*log_rotate_count/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH) date=$(sed '/^[ ]*log_rotate_date/!d;s/.*://;s/ *//' "$EJABBERD_CONFIG_PATH")
date=$(sed '/^[ ]*log_rotate_date/!d;s/.*://;s/ *//' $EJABBERD_CONFIG_PATH)
else
rate=$(sed '/^[ ]*log_rate_limit/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
rotate=$(sed '/^[ ]*log_rotate_size/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
count=$(sed '/^[ ]*log_rotate_count/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
date=$(sed '/^[ ]*log_rotate_date/!d;s/.*,//;s/ *//;s/}\.//' $EJABBERD_CONFIG_PATH)
fi
[ -z "$rate" ] || EJABBERD_OPTS="log_rate_limit $rate" [ -z "$rate" ] || EJABBERD_OPTS="log_rate_limit $rate"
[ -z "$rotate" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_size $rotate" [ -z "$rotate" ] || EJABBERD_OPTS="$EJABBERD_OPTS log_rotate_size $rotate"
[ -z "$count" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_count $count" [ -z "$count" ] || EJABBERD_OPTS="$EJABBERD_OPTS log_rotate_count $count"
[ -z "$date" ] || EJABBERD_OPTS="${EJABBERD_OPTS} log_rotate_date '$date'" [ -z "$date" ] || EJABBERD_OPTS="$EJABBERD_OPTS log_rotate_date '$date'"
[ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd ${EJABBERD_OPTS}" [ -z "$EJABBERD_OPTS" ] || EJABBERD_OPTS="-ejabberd $EJABBERD_OPTS"
EJABBERD_OPTS="-mnesia dir \"$SPOOL_DIR\" $MNESIA_OPTIONS $EJABBERD_OPTS -s ejabberd"
[ -d "$SPOOL_DIR" ] || $EXEC_CMD "mkdir -p $SPOOL_DIR"
cd "$SPOOL_DIR"
# export global variables # export global variables
export EJABBERD_CONFIG_PATH export EJABBERD_CONFIG_PATH
export EJABBERD_LOG_PATH export EJABBERD_LOG_PATH
export EJABBERD_BIN_PATH
export EJABBERD_DOC_PATH export EJABBERD_DOC_PATH
export EJABBERD_PID_PATH export EJABBERD_PID_PATH
export ERL_CRASH_DUMP export ERL_CRASH_DUMP
@ -174,89 +110,26 @@ export CONTRIB_MODULES_PATH
export CONTRIB_MODULES_CONF_DIR export CONTRIB_MODULES_CONF_DIR
export ERL_LIBS export ERL_LIBS
# TODO: Too much copy-and-paste below, factorize! # run command either directly or via su $INSTALLUSER
# start server exec_cmd()
start()
{ {
check_start case $EXEC_CMD in
exec_cmd $ERL \ as_install_user) su -c '"$0" $@"' "$INSTALLUSER" -- "$@" ;;
$NAME $ERLANG_NODE \ as_current_user) "$@" ;;
-noinput -detached \ esac
$MNESIA_OPTS \ }
$KERNEL_OPTS \ exec_erl()
$EJABBERD_OPTS \ {
-s ejabberd \ NODE=$1; shift
$ERLANG_OPTS \ exec_cmd $ERL $NAME $NODE $ERLANG_OPTS "$@"
"$@" }
} exec_iex()
{
# attach to server NODE=$1; shift
debug() exec_cmd $IEX -$NAME $NODE --erl "$ERLANG_OPTS" "$@"
{
debugwarning
NID=$(uid debug)
exec_cmd $ERL $NAME $NID \
-remsh $ERLANG_NODE \
-hidden \
$KERNEL_OPTS \
$ERLANG_OPTS \
"$@"
}
# attach to server using Elixir
iexdebug()
{
debugwarning
# Elixir shell is hidden as default
NID=$(uid debug)
exec_cmd $IEX $IEXNAME $NID \
-remsh "$ERLANG_NODE" \
--erl "$KERNEL_OPTS" \
--erl "$ERLANG_OPTS" \
--erl "$@"
}
# start interactive server
live()
{
livewarning
exec_cmd $ERL $NAME $ERLANG_NODE \
$MNESIA_OPTS \
$KERNEL_OPTS \
$EJABBERD_OPTS \
-s ejabberd \
$ERLANG_OPTS \
"$@"
}
# start interactive server with Elixir
iexlive()
{
livewarning
echo $@
exec_cmd $IEX $IEXNAME $ERLANG_NODE \
--erl "-mnesia dir \"$SPOOL_DIR\"" \
--erl "$KERNEL_OPTS" \
--erl "$EJABBERD_OPTS" \
--app ejabberd \
--erl "$ERLANG_OPTS" \
--erl "$@"
}
# start server in the foreground
foreground()
{
check_start
exec_cmd $ERL $NAME $ERLANG_NODE \
-noinput \
$MNESIA_OPTS \
$KERNEL_OPTS \
$EJABBERD_OPTS \
-s ejabberd \
$ERLANG_OPTS \
"$@"
} }
# usage
debugwarning() debugwarning()
{ {
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
@ -283,7 +156,6 @@ debugwarning()
livewarning() livewarning()
{ {
check_start
if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then if [ "$EJABBERD_BYPASS_WARNINGS" != "true" ] ; then
echo "--------------------------------------------------------------------" echo "--------------------------------------------------------------------"
echo "" echo ""
@ -305,32 +177,6 @@ livewarning()
fi fi
} }
etop()
{
NID=$(uid top)
exec_cmd $ERL \
$NAME $NID \
-hidden -s etop -s erlang halt -output text -node $ERLANG_NODE
}
ping()
{
[ -z "$1" ] && PEER=${ERLANG_NODE} || PEER=$1
if [ "$PEER" = "${PEER%.*}" ] ; then
PING_NAME="-sname"
PING_NODE=$(hostname -s)
else
PING_NAME="-name"
PING_NODE=$(hostname)
fi
NID=$(uid ping ${PING_NODE})
exec_cmd $ERL \
$PING_NAME $NID \
-hidden $KERNEL_OPTS $ERLANG_OPTS \
-eval 'io:format("~p~n",[net_adm:ping('"$PEER"')])' \
-s erlang halt -output text -noinput
}
help() help()
{ {
echo "" echo ""
@ -352,28 +198,27 @@ help()
echo "" echo ""
} }
# common control function # generic erlang node ping feature
ctl() ping()
{ {
NID=$(uid ctl) PEER=${1:-$ERLANG_NODE}
exec_cmd $ERL $NAME $NID \ if [ "$PEER" = "${PEER%.*}" ] ; then
-noinput -hidden $KERNEL_OPTS -s ejabberd_ctl \ PING_NAME="-sname"
-extra $ERLANG_NODE $EJABBERD_NO_TIMEOUT \ PING_NODE=$(hostname -s)
"$@" else
result=$? PING_NAME="-name"
case $result in PING_NODE=$(hostname)
2) help;; fi
3) help;; exec_cmd $ERL $PING_NAME $(uid ping $PING_NODE) $ERLANG_OPTS \
*) :;; -noinput -hidden -eval 'io:format("~p~n",[net_adm:ping('"$PEER"')])' \
esac -s erlang halt -output text
return $result
} }
# dynamic node name helper
uid() uid()
{ {
uuid=$(uuidgen 2>/dev/null) uuid=$(uuidgen 2>/dev/null)
[ -z "$uuid" -a -f /proc/sys/kernel/random/uuid ] && \ [ -z "$uuid" -a -f /proc/sys/kernel/random/uuid ] && uuid=$(cat /proc/sys/kernel/random/uuid)
uuid=$(cat /proc/sys/kernel/random/uuid)
[ -z "$uuid" ] && uuid=$(printf "%X" $RANDOM$(date +%M%S)$$) [ -z "$uuid" ] && uuid=$(printf "%X" $RANDOM$(date +%M%S)$$)
uuid=${uuid%%-*} uuid=${uuid%%-*}
[ $# -eq 0 ] && echo ${uuid}-${ERLANG_NODE} [ $# -eq 0 ] && echo ${uuid}-${ERLANG_NODE}
@ -388,6 +233,7 @@ stop_epmd()
} }
# make sure node not already running and node name unregistered # make sure node not already running and node name unregistered
# if all ok, ensure runtime directory exists and make it current directory
check_start() check_start()
{ {
"$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && { "$EPMD" -names 2>/dev/null | grep -q " ${ERLANG_NODE%@*} " && {
@ -404,11 +250,16 @@ check_start()
"$EPMD" -kill >/dev/null "$EPMD" -kill >/dev/null
} }
} }
} || {
cd "$SPOOL_DIR" || {
echo "ERROR: ejabberd can not access directory $SPOOL_DIR"
exit 6
}
} }
} }
# allow sync calls # allow sync calls
wait_for_status() wait_status()
{ {
# args: status try delay # args: status try delay
# return: 0 OK, 1 KO # return: 0 OK, 1 KO
@ -417,27 +268,64 @@ wait_for_status()
while [ $status -ne $1 ] ; do while [ $status -ne $1 ] ; do
sleep $3 sleep $3
timeout=`expr $timeout - 1` timeout=`expr $timeout - 1`
[ $timeout -eq 0 ] && { if [ $timeout -eq 0 ] ; then
status=$1 status=$1
} || { else
ctl status > /dev/null ctl status > /dev/null
status=$? status=$?
} fi
done done
[ $timeout -eq 0 ] && return 1 || return 0 [ $timeout -gt 0 ]
} }
# main handler # main
case $@ in case $1 in
'start') start;; start)
'debug') debug;; check_start
'iexdebug') iexdebug;; exec_erl $ERLANG_NODE $EJABBERD_OPTS -noinput -detached
'live') live;; ;;
'iexlive') iexlive;; foreground)
'foreground') foreground;; check_start
'ping'*) shift; ping "$@";; exec_erl $ERLANG_NODE $EJABBERD_OPTS -noinput
'etop') etop;; ;;
'started') wait_for_status 0 30 2;; # wait 30x2s before timeout live)
'stopped') wait_for_status 3 30 2 && stop_epmd;; # wait 30x2s before timeout livewarning
*) ctl "$@";; check_start
exec_erl $ERLANG_NODE $EJABBERD_OPTS
;;
debug)
debugwarning
exec_erl $(uid debug) -hidden -remsh $ERLANG_NODE
;;
etop)
exec_erl $(uid top) -hidden -node $ERLANG_NODE -s etop \
-s erlang halt -output text
;;
iexdebug)
debugwarning
exec_iex $(uid debug) --remsh "$ERLANG_NODE"
;;
iexlive)
livewarning
exec_iex $ERLANG_NODE --erl "$EJABBERD_OPTS" --app ejabberd
;;
ping)
ping $2
;;
started)
wait_status 0 30 2 # wait 30x2s before timeout
;;
stopped)
wait_status 3 30 2 && stop_epmd # wait 30x2s before timeout
;;
*)
exec_erl $(uid ctl) -hidden -noinput -s ejabberd_ctl \
-extra $ERLANG_NODE $NO_TIMEOUT "$@"
result=$?
case $result in
2|3) help;;
*) :;;
esac
exit $result
;;
esac esac