feat: support HAProxy protocol for dashboard API
This commit is contained in:
parent
74ae7c4264
commit
fb763ecebd
|
@ -92,6 +92,16 @@ Note: `sample_interval` should be a divisor of 60."""
|
||||||
zh: "IPv6 only"
|
zh: "IPv6 only"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
proxy_header {
|
||||||
|
desc {
|
||||||
|
en: "Enable support for HAProxy header. Be aware once enabled regular HTTP requests can't be handled anymore."
|
||||||
|
zh: "[FIXME]"
|
||||||
|
}
|
||||||
|
label: {
|
||||||
|
en: "Enable support for HAProxy header"
|
||||||
|
zh: "[FIXME]"
|
||||||
|
}
|
||||||
|
}
|
||||||
desc_dashboard {
|
desc_dashboard {
|
||||||
desc {
|
desc {
|
||||||
en: "Configuration for EMQX dashboard."
|
en: "Configuration for EMQX dashboard."
|
||||||
|
|
|
@ -92,8 +92,8 @@ start_listeners(Listeners) ->
|
||||||
},
|
},
|
||||||
Res =
|
Res =
|
||||||
lists:foldl(
|
lists:foldl(
|
||||||
fun({Name, Protocol, Bind, RanchOptions}, Acc) ->
|
fun({Name, Protocol, Bind, RanchOptions, ProtoOpts}, Acc) ->
|
||||||
Minirest = BaseMinirest#{protocol => Protocol},
|
Minirest = BaseMinirest#{protocol => Protocol, protocol_options => ProtoOpts},
|
||||||
case minirest:start(Name, RanchOptions, Minirest) of
|
case minirest:start(Name, RanchOptions, Minirest) of
|
||||||
{ok, _} ->
|
{ok, _} ->
|
||||||
?ULOG("Listener ~ts on ~ts started.~n", [
|
?ULOG("Listener ~ts on ~ts started.~n", [
|
||||||
|
@ -125,7 +125,7 @@ stop_listeners(Listeners) ->
|
||||||
?SLOG(warning, #{msg => "stop_listener_failed", name => Name, port => Port})
|
?SLOG(warning, #{msg => "stop_listener_failed", name => Name, port => Port})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|| {Name, _, Port, _} <- listeners(Listeners)
|
|| {Name, _, Port, _, _} <- listeners(Listeners)
|
||||||
],
|
],
|
||||||
ok.
|
ok.
|
||||||
|
|
||||||
|
@ -164,7 +164,13 @@ listeners(Listeners) ->
|
||||||
maps:get(enable, Conf) andalso
|
maps:get(enable, Conf) andalso
|
||||||
begin
|
begin
|
||||||
{Conf1, Bind} = ip_port(Conf),
|
{Conf1, Bind} = ip_port(Conf),
|
||||||
{true, {listener_name(Protocol), Protocol, Bind, ranch_opts(Conf1)}}
|
{true, {
|
||||||
|
listener_name(Protocol),
|
||||||
|
Protocol,
|
||||||
|
Bind,
|
||||||
|
ranch_opts(Conf1),
|
||||||
|
proto_opts(Conf1)
|
||||||
|
}}
|
||||||
end
|
end
|
||||||
end,
|
end,
|
||||||
maps:to_list(Listeners)
|
maps:to_list(Listeners)
|
||||||
|
@ -197,7 +203,7 @@ ranch_opts(Options) ->
|
||||||
SocketOpts = maps:fold(
|
SocketOpts = maps:fold(
|
||||||
fun filter_false/3,
|
fun filter_false/3,
|
||||||
[],
|
[],
|
||||||
maps:without([enable, inet6, ipv6_v6only | Keys], Options)
|
maps:without([enable, inet6, ipv6_v6only, proxy_header | Keys], Options)
|
||||||
),
|
),
|
||||||
InetOpts =
|
InetOpts =
|
||||||
case Options of
|
case Options of
|
||||||
|
@ -210,6 +216,9 @@ ranch_opts(Options) ->
|
||||||
end,
|
end,
|
||||||
RanchOpts#{socket_opts => InetOpts ++ SocketOpts}.
|
RanchOpts#{socket_opts => InetOpts ++ SocketOpts}.
|
||||||
|
|
||||||
|
proto_opts(Options) ->
|
||||||
|
maps:with([proxy_header], Options).
|
||||||
|
|
||||||
filter_false(_K, false, S) -> S;
|
filter_false(_K, false, S) -> S;
|
||||||
filter_false(K, V, S) -> [{K, V} | S].
|
filter_false(K, V, S) -> [{K, V} | S].
|
||||||
|
|
||||||
|
|
|
@ -160,6 +160,14 @@ common_listener_fields() ->
|
||||||
default => false,
|
default => false,
|
||||||
desc => ?DESC(ipv6_v6only)
|
desc => ?DESC(ipv6_v6only)
|
||||||
}
|
}
|
||||||
|
)},
|
||||||
|
{"proxy_header",
|
||||||
|
?HOCON(
|
||||||
|
boolean(),
|
||||||
|
#{
|
||||||
|
desc => ?DESC(proxy_header),
|
||||||
|
default => false
|
||||||
|
}
|
||||||
)}
|
)}
|
||||||
].
|
].
|
||||||
|
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
-export([
|
-export([
|
||||||
set_default_config/0,
|
set_default_config/0,
|
||||||
set_default_config/1,
|
set_default_config/1,
|
||||||
|
set_default_config/2,
|
||||||
request/2,
|
request/2,
|
||||||
request/3,
|
request/3,
|
||||||
request/4,
|
request/4,
|
||||||
|
@ -36,6 +37,9 @@ set_default_config() ->
|
||||||
set_default_config(<<"admin">>).
|
set_default_config(<<"admin">>).
|
||||||
|
|
||||||
set_default_config(DefaultUsername) ->
|
set_default_config(DefaultUsername) ->
|
||||||
|
set_default_config(DefaultUsername, false).
|
||||||
|
|
||||||
|
set_default_config(DefaultUsername, HAProxyEnabled) ->
|
||||||
Config = #{
|
Config = #{
|
||||||
listeners => #{
|
listeners => #{
|
||||||
http => #{
|
http => #{
|
||||||
|
@ -46,7 +50,8 @@ set_default_config(DefaultUsername) ->
|
||||||
max_connections => 512,
|
max_connections => 512,
|
||||||
num_acceptors => 4,
|
num_acceptors => 4,
|
||||||
send_timeout => 5000,
|
send_timeout => 5000,
|
||||||
backlog => 512
|
backlog => 512,
|
||||||
|
proxy_header => HAProxyEnabled
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
default_username => DefaultUsername,
|
default_username => DefaultUsername,
|
||||||
|
|
|
@ -0,0 +1,83 @@
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
%% Copyright (c) 2020-2023 EMQ Technologies Co., Ltd. All Rights Reserved.
|
||||||
|
%%
|
||||||
|
%% Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
%% you may not use this file except in compliance with the License.
|
||||||
|
%% You may obtain a copy of the License at
|
||||||
|
%%
|
||||||
|
%% http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
%%
|
||||||
|
%% Unless required by applicable law or agreed to in writing, software
|
||||||
|
%% distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
%% See the License for the specific language governing permissions and
|
||||||
|
%% limitations under the License.
|
||||||
|
%%--------------------------------------------------------------------
|
||||||
|
|
||||||
|
-module(emqx_dashboard_haproxy_SUITE).
|
||||||
|
|
||||||
|
-compile(nowarn_export_all).
|
||||||
|
-compile(export_all).
|
||||||
|
|
||||||
|
-import(
|
||||||
|
emqx_common_test_http,
|
||||||
|
[
|
||||||
|
request_api/3
|
||||||
|
]
|
||||||
|
).
|
||||||
|
|
||||||
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
-include("emqx_dashboard.hrl").
|
||||||
|
|
||||||
|
-define(HOST, "http://127.0.0.1:18083").
|
||||||
|
|
||||||
|
-define(BASE_PATH, "/").
|
||||||
|
|
||||||
|
all() ->
|
||||||
|
emqx_common_test_helpers:all(?MODULE).
|
||||||
|
|
||||||
|
end_suite() ->
|
||||||
|
end_suite([]).
|
||||||
|
|
||||||
|
end_suite(Apps) ->
|
||||||
|
application:unload(emqx_management),
|
||||||
|
mnesia:clear_table(?ADMIN),
|
||||||
|
emqx_common_test_helpers:stop_apps(Apps ++ [emqx_dashboard]).
|
||||||
|
|
||||||
|
init_per_suite(Config) ->
|
||||||
|
emqx_common_test_helpers:start_apps(
|
||||||
|
[emqx_management, emqx_dashboard],
|
||||||
|
fun set_special_configs/1
|
||||||
|
),
|
||||||
|
Config.
|
||||||
|
|
||||||
|
end_per_suite(_Config) ->
|
||||||
|
emqx_common_test_helpers:stop_apps([emqx_dashboard, emqx_management]),
|
||||||
|
mria:stop().
|
||||||
|
|
||||||
|
set_special_configs(emqx_dashboard) ->
|
||||||
|
emqx_dashboard_api_test_helpers:set_default_config(<<"admin">>, true),
|
||||||
|
ok;
|
||||||
|
set_special_configs(_) ->
|
||||||
|
ok.
|
||||||
|
|
||||||
|
disabled_t_status(_) ->
|
||||||
|
%% no easy way since httpc doesn't support emulating the haproxy protocol
|
||||||
|
{ok, 200, _Res} = http_get(["status"]),
|
||||||
|
ok.
|
||||||
|
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
%% Internal functions
|
||||||
|
%%------------------------------------------------------------------------------
|
||||||
|
http_get(Parts) ->
|
||||||
|
request_api(get, api_path(Parts), auth_header_()).
|
||||||
|
|
||||||
|
auth_header_() ->
|
||||||
|
auth_header_(<<"admin">>, <<"public">>).
|
||||||
|
|
||||||
|
auth_header_(Username, Password) ->
|
||||||
|
{ok, Token} = emqx_dashboard_admin:sign_token(Username, Password),
|
||||||
|
{"Authorization", "Bearer " ++ binary_to_list(Token)}.
|
||||||
|
|
||||||
|
api_path(Parts) ->
|
||||||
|
?HOST ++ filename:join([?BASE_PATH | Parts]).
|
|
@ -58,7 +58,7 @@
|
||||||
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.13.7"}}}
|
, {ekka, {git, "https://github.com/emqx/ekka", {tag, "0.13.7"}}}
|
||||||
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.8.1"}}}
|
, {gen_rpc, {git, "https://github.com/emqx/gen_rpc", {tag, "2.8.1"}}}
|
||||||
, {grpc, {git, "https://github.com/emqx/grpc-erl", {tag, "0.6.7"}}}
|
, {grpc, {git, "https://github.com/emqx/grpc-erl", {tag, "0.6.7"}}}
|
||||||
, {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.3.7"}}}
|
, {minirest, {git, "https://github.com/emqx/minirest", {tag, "1.3.8"}}}
|
||||||
, {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.2"}}}
|
, {ecpool, {git, "https://github.com/emqx/ecpool", {tag, "0.5.2"}}}
|
||||||
, {replayq, {git, "https://github.com/emqx/replayq.git", {tag, "0.3.5"}}}
|
, {replayq, {git, "https://github.com/emqx/replayq.git", {tag, "0.3.5"}}}
|
||||||
, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}
|
, {pbkdf2, {git, "https://github.com/emqx/erlang-pbkdf2.git", {tag, "2.0.4"}}}
|
||||||
|
|
Loading…
Reference in New Issue