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