mirror of
https://github.com/processone/ejabberd
synced 2025-10-03 17:59:31 +02:00
New ejabberdctl option CTL_OVER_HTTP
This uses an HTTP connection to execute the command, which is way faster than starting an erlang node
This commit is contained in:
parent
ab8a39e71f
commit
46a64c0f68
3 changed files with 96 additions and 16 deletions
|
@ -198,6 +198,17 @@
|
||||||
#
|
#
|
||||||
#CONTRIB_MODULES_CONF_DIR=/etc/ejabberd/modules
|
#CONTRIB_MODULES_CONF_DIR=/etc/ejabberd/modules
|
||||||
|
|
||||||
|
#.
|
||||||
|
#' CTL_OVER_HTTP: Path to ejabberdctl HTTP listener socket
|
||||||
|
#
|
||||||
|
# To speedup ejabberdctl execution time for ejabberd commands,
|
||||||
|
# you can setup an ejabberd_http listener with ejabberd_ctl handling requests,
|
||||||
|
# listening in a unix domain socket.
|
||||||
|
#
|
||||||
|
# Default: disabled
|
||||||
|
#
|
||||||
|
#CTL_OVER_HTTP=sockets/ctl_over_http.sock
|
||||||
|
|
||||||
#.
|
#.
|
||||||
#'
|
#'
|
||||||
# vim: foldmarker=#',#. foldmethod=marker:
|
# vim: foldmarker=#',#. foldmethod=marker:
|
||||||
|
|
|
@ -334,6 +334,47 @@ wait_status()
|
||||||
[ $timeout -gt 0 ]
|
[ $timeout -gt 0 ]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
exec_other_command()
|
||||||
|
{
|
||||||
|
if [ -z "$CTL_OVER_HTTP" ] || [ ! -S "$CTL_OVER_HTTP" ] \
|
||||||
|
|| [ ! -x "$(command -v curl)" ] || [ -z "$1" ] || [ "$1" = "help" ] \
|
||||||
|
|| [ "$1" = "mnesia_info_ctl" ]|| [ "$1" = "print_sql_schema" ] ; then
|
||||||
|
exec_erl "$(uid ctl)" -hidden -noinput \
|
||||||
|
-eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \
|
||||||
|
-s ejabberd_ctl \
|
||||||
|
-extra "$ERLANG_NODE" $NO_TIMEOUT "$@"
|
||||||
|
result=$?
|
||||||
|
case $result in
|
||||||
|
3) help;;
|
||||||
|
*) :;;
|
||||||
|
esac
|
||||||
|
exit $result
|
||||||
|
else
|
||||||
|
exec_ctl_over_http_socket "$@"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
exec_ctl_over_http_socket()
|
||||||
|
{
|
||||||
|
CARGS='{"ctl-command-line": "'${*}'"}'
|
||||||
|
TEMPHEADERS=temp-headers.log
|
||||||
|
curl \
|
||||||
|
--unix-socket ${CTL_OVER_HTTP} \
|
||||||
|
--header "Content-Type: application/json" \
|
||||||
|
--header "Accept: application/json" \
|
||||||
|
--data "${CARGS}" \
|
||||||
|
--dump-header ${TEMPHEADERS} \
|
||||||
|
--no-progress-meter \
|
||||||
|
"http://localhost/ctl/${1}"
|
||||||
|
result=$(sed -n 's/.*status-code: \([0-9]*\).*/\1/p' < $TEMPHEADERS)
|
||||||
|
rm ${TEMPHEADERS}
|
||||||
|
case $result in
|
||||||
|
2|3) exec_other_command help ${1};;
|
||||||
|
*) :;;
|
||||||
|
esac
|
||||||
|
exit $result
|
||||||
|
}
|
||||||
|
|
||||||
# ensure we can change current directory to SPOOL_DIR
|
# ensure we can change current directory to SPOOL_DIR
|
||||||
[ -d "$SPOOL_DIR" ] || exec_cmd mkdir -p "$SPOOL_DIR"
|
[ -d "$SPOOL_DIR" ] || exec_cmd mkdir -p "$SPOOL_DIR"
|
||||||
cd "$SPOOL_DIR" || {
|
cd "$SPOOL_DIR" || {
|
||||||
|
@ -402,15 +443,6 @@ case $1 in
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
set_dist_client
|
set_dist_client
|
||||||
exec_erl "$(uid ctl)" -hidden -noinput \
|
exec_other_command "$@"
|
||||||
-eval 'net_kernel:connect_node('"'$ERLANG_NODE'"')' \
|
|
||||||
-s ejabberd_ctl \
|
|
||||||
-extra "$ERLANG_NODE" $NO_TIMEOUT "$@"
|
|
||||||
result=$?
|
|
||||||
case $result in
|
|
||||||
2|3) help;;
|
|
||||||
*) :;;
|
|
||||||
esac
|
|
||||||
exit $result
|
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
|
|
|
@ -28,7 +28,7 @@
|
||||||
-behaviour(gen_server).
|
-behaviour(gen_server).
|
||||||
-author('alexey@process-one.net').
|
-author('alexey@process-one.net').
|
||||||
|
|
||||||
-export([start/0, start_link/0, process/1, process2/2]).
|
-export([start/0, start_link/0, process/1, process/2, process2/2]).
|
||||||
%% gen_server callbacks
|
%% gen_server callbacks
|
||||||
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
-export([init/1, handle_call/3, handle_cast/2, handle_info/2,
|
||||||
terminate/2, code_change/3]).
|
terminate/2, code_change/3]).
|
||||||
|
@ -37,6 +37,7 @@
|
||||||
|
|
||||||
-include("ejabberd_ctl.hrl").
|
-include("ejabberd_ctl.hrl").
|
||||||
-include("ejabberd_commands.hrl").
|
-include("ejabberd_commands.hrl").
|
||||||
|
-include("ejabberd_http.hrl").
|
||||||
-include("logger.hrl").
|
-include("logger.hrl").
|
||||||
-include("ejabberd_stacktrace.hrl").
|
-include("ejabberd_stacktrace.hrl").
|
||||||
|
|
||||||
|
@ -115,15 +116,51 @@ code_change(_OldVsn, State, _Extra) ->
|
||||||
{ok, State}.
|
{ok, State}.
|
||||||
|
|
||||||
%%-----------------------------
|
%%-----------------------------
|
||||||
%% Process
|
%% Process http
|
||||||
|
%%-----------------------------
|
||||||
|
|
||||||
|
-spec process_http([binary()], tuple()) -> {non_neg_integer(), [{binary(), binary()}], string()}.
|
||||||
|
|
||||||
|
process_http([Call], #request{data = Data} = Request) when is_binary(Call) and is_record(Request, request) ->
|
||||||
|
[{<<"ctl-command-line">>, LineBin}] = extract_args(Data),
|
||||||
|
LineStrings = string:split(binary_to_list(LineBin), " ", all),
|
||||||
|
process_http2(LineStrings, ?DEFAULT_VERSION).
|
||||||
|
|
||||||
|
process_http2(["--version", Arg | Args], _) ->
|
||||||
|
Version =
|
||||||
|
try
|
||||||
|
list_to_integer(Arg)
|
||||||
|
catch _:_ ->
|
||||||
|
throw({invalid_version, Arg})
|
||||||
|
end,
|
||||||
|
process_http2(Args, Version);
|
||||||
|
|
||||||
|
process_http2(Args, Version) ->
|
||||||
|
{String, Code} = process2(Args, [], Version),
|
||||||
|
String2 = case String of
|
||||||
|
[] -> String;
|
||||||
|
_ -> [String, "\n"]
|
||||||
|
end,
|
||||||
|
{200, [{<<"status-code">>, integer_to_binary(Code)}], String2}.
|
||||||
|
|
||||||
|
%% Be tolerant to make API more easily usable from command-line pipe.
|
||||||
|
extract_args(<<"\n">>) -> [];
|
||||||
|
extract_args(Data) ->
|
||||||
|
Maps = misc:json_decode(Data),
|
||||||
|
maps:to_list(Maps).
|
||||||
|
|
||||||
|
%%-----------------------------
|
||||||
|
%% Process command line
|
||||||
%%-----------------------------
|
%%-----------------------------
|
||||||
|
|
||||||
-spec process([string()]) -> non_neg_integer().
|
-spec process([string()]) -> non_neg_integer().
|
||||||
process(Args) ->
|
process(Args) ->
|
||||||
process(Args, ?DEFAULT_VERSION).
|
process(Args, ?DEFAULT_VERSION).
|
||||||
|
|
||||||
|
-spec process([string() | binary()], non_neg_integer() | tuple()) -> non_neg_integer().
|
||||||
|
|
||||||
-spec process([string()], non_neg_integer()) -> non_neg_integer().
|
process([Call], Request) when is_binary(Call) and is_record(Request, request) ->
|
||||||
|
process_http([Call], Request);
|
||||||
|
|
||||||
%% The commands status, stop and restart are defined here to ensure
|
%% The commands status, stop and restart are defined here to ensure
|
||||||
%% they are usable even if ejabberd is completely stopped.
|
%% they are usable even if ejabberd is completely stopped.
|
||||||
|
@ -232,7 +269,7 @@ process2(Args, AccessCommands, Auth, Version) ->
|
||||||
io:format(lists:flatten(["\n" | String]++["\n"])),
|
io:format(lists:flatten(["\n" | String]++["\n"])),
|
||||||
[CommandString | _] = Args,
|
[CommandString | _] = Args,
|
||||||
process(["help" | [CommandString]], Version),
|
process(["help" | [CommandString]], Version),
|
||||||
{lists:flatten(String), ?STATUS_ERROR};
|
{lists:flatten(String), ?STATUS_USAGE};
|
||||||
{String, Code}
|
{String, Code}
|
||||||
when is_list(String) and is_integer(Code) ->
|
when is_list(String) and is_integer(Code) ->
|
||||||
{lists:flatten(String), Code};
|
{lists:flatten(String), Code};
|
||||||
|
@ -271,7 +308,7 @@ try_run_ctp(Args, Auth, AccessCommands, Version) ->
|
||||||
try_call_command(Args, Auth, AccessCommands, Version);
|
try_call_command(Args, Auth, AccessCommands, Version);
|
||||||
false ->
|
false ->
|
||||||
print_usage(Version),
|
print_usage(Version),
|
||||||
{"", ?STATUS_USAGE};
|
{"", ?STATUS_BADRPC};
|
||||||
Status ->
|
Status ->
|
||||||
{"", Status}
|
{"", Status}
|
||||||
catch
|
catch
|
||||||
|
@ -288,7 +325,7 @@ try_run_ctp(Args, Auth, AccessCommands, Version) ->
|
||||||
try_call_command(Args, Auth, AccessCommands, Version) ->
|
try_call_command(Args, Auth, AccessCommands, Version) ->
|
||||||
try call_command(Args, Auth, AccessCommands, Version) of
|
try call_command(Args, Auth, AccessCommands, Version) of
|
||||||
{Reason, wrong_command_arguments} ->
|
{Reason, wrong_command_arguments} ->
|
||||||
{Reason, ?STATUS_ERROR};
|
{Reason, ?STATUS_USAGE};
|
||||||
Res ->
|
Res ->
|
||||||
Res
|
Res
|
||||||
catch
|
catch
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue